Somehow I still think of lambdas as "syntactic sugar" for regular function objects, so it surprises me that under C++-20 a stateful but otherwise constexpr lambda instance cannot be used as a non-type template parameter, unlike an equivalent function object instance.
Can anyone explain this behavior or decision?
Example on godbolt:
struct always_fn {
const int x;
int operator()() const
{
return x;
}
};
inline constexpr always_fn always_f{5};
// lambda equivalent to `always_f`
inline constexpr auto always_2_f = [x = 5]() {
return x;
};
template<typename F>
struct wrapped {
F f_;
};
inline constexpr auto wrapped_f = wrapped{always_f};
inline constexpr auto wrapped_2_f = wrapped{always_2_f};
template<auto f>
void pass() {}
int main() {
pass<always_f>();
pass<wrapped_f>();
// error: no matching function for call to 'pass'
pass<always_2_f>();
// ^~~~~~~~~~~~~~~~
// error: no matching function for call to 'pass'
pass<wrapped_2_f>();
// ^~~~~~~~~~~~~~~~~
return 0;
}
Lambdas (whether stateful or not) are never structural types and therefore can never be used as non-type template argument.
This was clarified by CWG 2542 which compilers might not implement yet.
Without making such a decision, whether or not the lambda has a structural type would depend on implementation details such as whether the members of the closure type are private/public or the implementation of the closure type would have to be specified in much more detail.
In particular, there is nothing requiring that
xin your equivalent function object should be public and if it isn't, then it wouldn't be usable as non-type template argument either.