I get an error with the latest versions of clang and gcc with this code:
int main() {
auto lambda = [] (auto = [] {}) {};
lambda();
}
Clang gives the error:
prog.cc: In function 'int main()':
prog.cc:3:12: error: no match for call to '(main()::<lambda(auto:1)>) ()'
lambda();
^
prog.cc:2:35: note: candidate: template<class auto:1> main()::<lambda(auto:1)>
auto lambda = [] (auto = [] {}) {};
^
prog.cc:2:35: note: template argument deduction/substitution failed:
prog.cc:3:12: note: couldn't deduce template parameter 'auto:1'
lambda();
^
Why does this fail?
Since lambdas are sugar for functors, the issue is on the fact template functions are unable to deduce template arguments (
auto
) in this default context.A lambda can be reduced to the functor struct level by taking in consideration those statements:
§5.1.2/3 [expr.prim.lambda]
§5.1.2/5 [expr.prim.lambda]
As such the type of your lambda is equivalent to this functor type:
And your usage is then equivalent to:
The type of
Auto1
is unable to be inferred in this context as specified in §14.8.2.5/5 [temp.deduct.type]:Template functions (or methods) do not deduce their type parameters from their default arguments, and a closure with
auto
parameters is merely an object with a template method.This makes having a default lambda for a template function a bit annoying.
One approach would be to type erase calling an object, without storing it, like so:
As this just works with function pointers, and I have had good experience with gcc inlining simple function pointers, it might not have as high a performance impact as
std::function
. And unlikestd::function
no virtual tables or heap allocation is involved.live example
For a non-lambda, you can do this:
which deduces if you pass is an argument, and becomes a function-at-nothing if you don't. You could also do:
which might be easier to optimize.
Type deduction for
auto
does not consider default arguments.