1

I came across this curio and don't understand why the use of explicit constructors would cause this to fail.

I was trying to generate and initialize objects from configuration data using lambdas. I found that the lambda could only return a copy of the object if the object's class definition did not use explicit constructors. This code sample is a simplistic example of what I found.

class foo {
public:
    explicit foo() : _a(0) {}
    explicit foo(int val): _a(val) {}
    explicit foo(const foo& o) : _a(o._a) {}
    explicit foo(foo&& o) : _a(std::move(o._a)) {}
    foo& operator()(const foo& rhs) { if (this != &rhs) { _a = rhs._a; } return *this; }
    foo& operator()(foo&& rhs) { _a = std::move(rhs._a); return *this; }
    int a() const { return _a; }
    void a(int val) { _a = val; }
private:
    int _a;
};

auto makeFoo = [](int val) -> foo { return foo(val); };

As written the sample code fails to compile with the following errors on the makeFoo line:

In static member function ‘static foo<lambda(int)>::_FUN(int)’:
error: no matching function for call to ‘foo::foo(foo)’

However, if I remove the 'explicit' tags from the foo constructors, the code compiles just fine.

Can someone enlighten me as to why the constructors cannot be explicit in this lambda?

1 Answers1

2

First of all, review the documentation about the explicit keyword.

Specifies that a constructor or conversion function (since C++11) is explicit, that is, it cannot be used for implicit conversions and copy-initialization.

Basically, the explicit copy constructor means that the copy constructor will not be called implicitly.

You don't need to define your copy/move constructor, the compiler will generate them for you. Same for the copy/move assignment. Just remove them and you will be fine.

class foo {
public:
    foo() = default;
    explicit foo(int val): _a(val) {}
    int a() const { return _a; }
    void a(int val) { _a = val; }
private:
    int _a{0};
};
mohabouje
  • 3,867
  • 2
  • 14
  • 28
  • I'm aware that the compiler will create the copy/move constructors for me. That's not quite the issue I was asking about. It's more of why the return value balks when the constructors are explicit. I guess it didn't occur to me that the return value is still being _assigned_ even if there is a construction in that line of code, and explicit copy/move constructors prevent assignment. So, in general, the copy/move constructors should not be explicit. Initialization constructors could be. – jp jamieson Apr 07 '19 at 14:14