====== 2012.12.11 - lambdas vs. variadic templates ======
few days ago at work i had a need to write error handling mechanism in multiple methods. the thing was, that the methods themselves were short (usually 2-3 lines), while error handling consisted of multiple catch-es and some logging. there was also an //if(enabled)// to be added at the beginning. well -- excellent place for lambda! relevant fragment of the {{:blog:2012:12:11:example_handler.cpp|example handler program}} follows:
template
void errHandler(F f, bool enabled)
{
if(!enabled)
return;
try
{
f();
}
catch(Exception1 const&)
{
// bla bla
}
catch(Exception2 const&)
{
// bla bla
}
}
struct Example
{
void f1(std::string& str) const
{
auto l = [&](){ str+="?"; };
errHandler(l, enabled_);
}
void f2(std::string& str) const
{
auto l = [&](){ str+="!"; };
errHandler(l, enabled_);
}
bool enabled_ = true;
};
===== problem =====
it worked like a charm for all of the cases, except for one -- the call with the [[wp>variadic templates]]. in GCC 4.5 nor 4.7 variadic template parameters cannot be unpacked within the lambda body. namely this {{:blog:2012:12:11:lambda_vs_vartempl.cpp|example code}} does not compile, while it should:
template
void g(A...a)
{
std::cout << sizeof...(A) << std::endl;
}
template
void f(A...a)
{
auto l = [&]{ g(a...); }; // (clan)g++ Oops... :/
l();
}
===== compilers =====
gcc 4.7 produces following error message on that:
lambda_vs_vartempl.cpp: In lambda function:
lambda_vs_vartempl.cpp:13:19: error: parameter packs not expanded with ‘...’:
lambda_vs_vartempl.cpp:13:19: note: ‘a’
lambda_vs_vartempl.cpp:13:20: error: expansion pattern ‘a’ contains no argument packs
lambda_vs_vartempl.cpp: In instantiation of ‘void f(A ...) [with A = {double, double, int}]’:
lambda_vs_vartempl.cpp:19:20: required from here
lambda_vs_vartempl.cpp:13:26: error: using invalid field ‘f(A ...)::::__a’
lambda_vs_vartempl.cpp:13:26: error: unable to deduce ‘auto’ from ‘’
but wait - there's more! clang++ 3.0-6 outputs this:
0 libLLVM-3.0.so.1 0x00007f92a16984bf
1 libLLVM-3.0.so.1 0x00007f92a1698909
2 libpthread.so.0 0x00007f92a0618030
3 clang 0x0000000000a3083d clang::Sema::DeduceAutoType(clang::TypeSourceInfo*, clang::Expr*, clang::TypeSourceInfo*&) + 29
4 clang 0x00000000008b001d clang::Sema::AddInitializerToDecl(clang::Decl*, clang::Expr*, bool, bool) + 1533
5 clang 0x00000000008042ee clang::Parser::ParseDeclarationAfterDeclaratorAndAttributes(clang::Declarator&, clang::Parser::ParsedTemplateInfo const&) + 1790
// ...
21 clang 0x00000000005c121f clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 319
22 clang 0x00000000005a9a8a clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 1114
23 clang 0x00000000005a17a4 cc1_main(char const**, char const**, char const*, void*) + 804
24 clang 0x00000000005a0154 main + 596
25 libc.so.6 0x00007f929f6edead __libc_start_main + 253
26 clang 0x00000000005a1329
Stack dump:
// ...
1. lambda_vs_vartempl.cpp:13:27: current parser token ';'
2. lambda_vs_vartempl.cpp:12:1: parsing function body 'f'
3. lambda_vs_vartempl.cpp:12:1: in compound statement ('{}')
clang: error: unable to execute command: Segmentation fault
clang: error: clang frontend command failed due to signal 2 (use -v to see invocation)
clang: note: diagnostic msg: Please submit a bug report to http://llvm.org/bugs/ and include command line arguments and all diagnostic information.
clang: note: diagnostic msg: Preprocessed source(s) are located at:
clang: note: diagnostic msg: /tmp/lambda_vs_vartempl-XSkQV6.ii
===== final remarks =====
the good news, that lambda vs. variadic templates bugs are already reported [[http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226|1]] [[http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933|2]]. the bad news is both are already at least 2 years old... [[http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226#c2|gcc 4.8 is said not to fix this]] as well. [[wp>C++11]] is complex, after all... ;)