Consider the following:
#include <utility>
#include <string>
template<typename>
class C;
template<typename R, typename T>
class C<R(&)(T)> {
public:
template<typename F>
C(F&& fun) {}
};
template<typename T>
C<T> makeC(T&& fun) {
return C<T>(std::forward<T>(fun));
}
int foo(int a){return a;}
int main() {
auto p1 = makeC(foo); // OK
auto p2 = C<int(&)(int)>([](int a){return a;}); // OK
// auto p3 = makeC([](int a){return a;}); // FAIL
}
The declaration of p3
fails because the compiler can't infer the type int(&)(int)
from the lambda that was passed as parameter. p1
is ok because the type can be easily infered from the function foo
, and p2
is ok because the type is explicitly declared.
It fails with:
error: invalid use of incomplete type 'class C<main()::<lambda(int)> >'
Is there any way to make the compiler infer the function type corretly, given a lambda?
P.S.: C++17 answers are also ok, if applicable.
The actual problem is that a lambda function has it own type, that cannot be reduced to
R(&)(T)
. Because of that,C<T>
is an incomplete type as correctly outlined by the compiler.As long as you use non-capturing lambdas, you can rely on the fact that they decay to function pointers and do this:
Or this:
Another possible solution that works with capturing lambdas is this:
This way, when dealing with a lambda,
C
actually inherits from it and privately contains itsoperator()
.