Table of Contents

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 example handler program follows:

template<typename F>
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 variadic templates. in GCC 4.5 nor 4.7 variadic template parameters cannot be unpacked within the lambda body. namely this example code does not compile, while it should:

template<typename ...A>
void g(A...a)
{
  std::cout << sizeof...(A) << std::endl;
}
template<typename ...A>
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 ...)::<lambda()>::__a’
lambda_vs_vartempl.cpp:13:26: error: unable to deduce ‘auto’ from ‘<expression error>’

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 1 2. the bad news is both are already at least 2 years old… gcc 4.8 is said not to fix this as well. C++11 is complex, after all… ;)