Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this compile when passing a lambda in direct initialization and assignment but not with copy initialization?

Tags:

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([]() {      }); } 
like image 245
tuket Avatar asked Jun 15 '18 15:06

tuket


People also ask

Does copy-initialization call copy constructor?

In other words, a good compiler will not create a copy for copy-initialization when it can be avoided; instead it will just call the constructor directly -- ie, just like for direct-initialization.

What is the other name for copy-initialization?

Implicit conversion is defined in terms of copy-initialization: if an object of type T can be copy-initialized with expression E , then E is implicitly convertible to T . The equals sign, = , in copy-initialization of a named variable is not related to the assignment operator.


1 Answers

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.

like image 148
songyuanyao Avatar answered Jan 12 '23 03:01

songyuanyao