Hertz
Hertz

Reputation: 101

Move constructor template elision

For what reason move constructor call is not elided in following code?

struct Foo {
    Foo() = default;

    Foo(const Foo&) { cout << "Foo(const Foo&)" << endl; }
    template<class T> Foo(T&&) { cout << "Foo<T>(T&&)" << endl; }
};

auto f = Foo{};

Output: Foo<T>(T&&)

Checked on clang 3.3, g++ 4.9.

Adding defaulted or user-defined move constructor results in no output at all. Why the call to move constructor template is not elided by the compiler? And why the call to non-template one gets elided even if it's user-defined (i.e. how does the compiler know that it has no side-effects and can be safely elided)?

Upvotes: 1

Views: 317

Answers (2)

Hertz
Hertz

Reputation: 101

The reason is because copy and move constructors are defined to be non-template (12.8/2, 12.8/3), copy/move elision rules do not apply for this constructor template (12.8/31).

The addition of defaulted or user defined move constructor (in this case) results in different output (and move elision) because user-defined copy constructor prevents compiler from implicitly generating a default one, thus the answer was wrong in first place:

12.8/7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4).

Upvotes: 0

AProgrammer
AProgrammer

Reputation: 52314

To be a move constructor and thus candidate for elision, the constructor must not be a template instantiation (similarly, the fact that a template can generate a constructor with the same signature will not prevent the defaulted version to be generated).

In your example, the presence of the explicit copy constructor prevent the implicit generation of a default move constructor, so the constructor template is instantiated (and is not a move constructor even if it share the signature).

If you add an explicit (default or not) move constructor, it will be used (and can -- but not must -- be elided).

Upvotes: 4

Related Questions