I would like to compile the code below with c 17, so that I can pass any function (lambda) that has a specific signature, int(int)
, while also allowing the default argument:
template <class F = int(int)> // for deduction
struct A{
A(F f = [] (int x){return x;}) : f_{f} {}
F f_;
};
int main() {
A work([](int x){return x 1;});
A not_work; // compile error.
}
However, clang emits an error:
a.cpp:6:4: error: data member instantiated with function type 'int (int)'
F f_;
^
a.cpp:11:4: note: in instantiation of template class 'A<int (int)>' requested here
A not_work;
^
I don't understand why the member f_
can be initialized when I pass the lambda and the default lambda argument cannot be?
Meanwhile, is there any better way to do this?
CodePudding user response:
As the error message said, you can't declare a data member with a function type like int(int)
.
When passing a lambda to the constructor, the template parameter F
would be deduced as the lambda closure type by CTAD (since C 17); when passing nothing F
will use the default argument int(int)
and the data member f_
's type would be int(int)
too, which causes the error.
You might use a function pointer type (lambdas without capture could convert to function pointer implicitly) or std::function<int(int)>
. E.g.
template <class F = int(*)(int)> // for deduction
struct A{
A(F f = [] (int x){return x;}) : f_{f} {}
F f_;
};
Or
template <class F = std::function<int(int)>> // for deduction
struct A{
A(F f = [] (int x){return x;}) : f_{f} {}
F f_;
};