Reputation: 3951
Why doesn't assignment operator allow for a lambda expression when done in the same line the object is declared?
It seems to be working in MSVC though.
Test the code: https://godbolt.org/g/n2Tih1
class Func
{
typedef void(*func_type)();
func_type m_f;
public:
Func() {}
Func(func_type f) : m_f(f) {}
Func operator=(func_type f) {
m_f = f;
return *this;
}
};
int main()
{
// doesn't compile in GCC and clang, it does in MSVC
Func f1 = []() {
};
// compiles!
Func f2;
f2 = []() {
};
// compiles!
Func f3([]() {
});
}
Upvotes: 23
Views: 1026
Reputation: 172964
Func f1 = []() {};
is copy initialization, which requires two user-defined implicit conversion to construct f1
, the 1st one is from the lambda to the function pointer, the 2nd one is from the function pointer to Func
. Only one user-defined implicit conversion is allowed in one conversion sequence so it fails.
(emphasis mine)
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution.
and
Implicit conversion sequence consists of the following, in this order:
1) zero or one standard conversion sequence;
2) zero or one user-defined conversion;
3) zero or one standard conversion sequence.
For f2 = []() {};
the appropriate assignment operator is tried to be called, Func
has one and it expects the function pointer as the argument; only one implicit conversion from the lambda to function pointer is required and then it works well.
Func f3([]() {});
is direct initialization, the appropriate constructor is tried to be called, Func
has one and it expects the function pointer as the argument. Then it's the same as f2
.
You may get the point from the difference between copy initialization and direct initialization.
In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.
Upvotes: 22
Reputation: 29022
Your first case involves two implicit conversions, lambda to void(*)()
then void(*)()
to Func
. You can have at most 1 implicit conversion.
If you can eliminate one of the implicit conversions it should work fine. Here are some potential solutions you can try :
// Explicit cast to a function pointer
Func f1 = static_cast<void(*)()>([]() {});
// func_ptr is already a function pointer
// eliminating one of the implcit conversions
void (*func_ptr)() = [](){};
Func f2 = func_ptr;
// The conversion from `void(*)()` is no longer implicit
Func f3{ [](){} };
Upvotes: 8