Lambda extension for each parameter of the parameter package: Clang vs. Gcc

This code works fine in Clang 3.5:

#include <iostream> #include <string> void callFuncs() {} template<typename Func, typename ...Funcs> void callFuncs(const Func &func, const Funcs &...funcs) { func(); callFuncs(funcs...); } template<typename ...Types> void callPrintFuncs() { callFuncs(([] { std::cout << Types() << std::endl; })...); } int main() { callPrintFuncs<int, float, double, std::string>(); } 

However, in GCC 4.9, the following error occurs instead:

 test.cpp: In lambda function: test.cpp:16:54: error: parameter packs not expanded with '...': callFuncs(([] { std::cout << Types() << std::endl; })...); ^ test.cpp:16:54: note: 'Types' test.cpp: In function 'void callPrintFuncs()': test.cpp:16:58: error: expansion pattern '<lambda>' contains no argument packs callFuncs(([] { std::cout << Types() << std::endl; })...); 

So, does the compiler have an error, Clang or GCC? Clan behavior is of the utmost importance to me.

+8
lambda c ++ 11 variadic-templates
source share
1 answer

gcc is here. There are rules in the standard against unpacked parameter packages, but the above parameter package is expanding.

It expands upon completion of the innermost statement in which it resides, but the standard does not require parameter packages to be expanded to the end of each statement.

The fact that gcc got it wrong is understandable; naively, you might think that a parameter package can only be inside a single statement, and a failure to expand at the end of the statement is fatal. But lambdas allows you to embed statements in statements.

A common workaround would be to pass in one lambda and pass it a tag type.

 template<class T>struct tag_t{using type=T;}; template<class Tag>using type_t=typename Tag::type; template<typename Func, typename ...Ts> void callOnEachOf(Func&&func, Ts&&...ts) { using discard=int[]; (void)discard{0,((void)( func(std::forward<Ts>(ts)) ),0)...}; } template<typename ...Types> void callPrintFuncs() { callOnEachOf( [](auto tag){ using Type=type_t<decltype(tag)>; std::cout << Type() << std::endl; }, tag_t<Types>... ); } 
+2
source share

All Articles