Considering the following code snippet:
template <typename TF>
void post(TF){ }
template <typename... TFs>
struct funcs : TFs...
{
funcs(TFs... fs) : TFs{fs}... { }
void call()
{
(post([&]{ static_cast<TFs&>(*this)(); }), ...);
}
};
clang++ 3.8+ successfully compiles the code.
g++ 7.0 fails to compile with the following error:
prog.cc: In lambda function:
prog.cc:10:43: error: parameter packs not expanded with '...':
(post([&]{ static_cast<TFs&>(*this)(); }), ...);
~~~~~~~~~~~~~~~~~~~~~~~~^~
prog.cc:10:43: note: 'TFs'
prog.cc: In member function 'void funcs<TFs>::call()':
prog.cc:10:13: error: operand of fold expression has no unexpanded parameter packs
(post([&]{ static_cast<TFs&>(*this)(); }), ...);
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Removing the post
call and the lambda makes g++ compile the fold expression.
Is this interaction between lambdas, fold expressions and template function calls somehow forbidden by the standard, or is this a gcc bug?
This is a well-known g++ bug (#47226) that was reported in... 2011.
This is an old gcc bug. It is one of the few cases where gcc's template handling is worse than MSVC. Shame gcc. Shame.
A workaround that sometimes works is to use tags and pack expansion.
where we carefully avoid expanding over the end of a lambda by passing the lambda in each time. Instead, we take a set of arguments and expand it into a set of lambda calls.
The lambda gets the types passed in as a tag, then we convert it back to a type.
Live example
Do not store return type of
expand
if you passed it temporaries.