Why does this compile when passing a lambda in the constructor but not with the assignment operator?

  • A+

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([]() {      }); } 


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.


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.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: