Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a templatised constructor stand in for a deleted copy constructor?

Tags:

c++

Consider

template<typename T>
struct Foo
{
    Foo(const Foo&) = delete;
    template <typename Y>
    Foo(const Foo<Y>&){}
};

Does the appropriate instantiation of the template constructor stand in for the copy constructor? I know it doesn't normally (since the copy constructor must not be a template function) but here I've deleted the copy constructor.

like image 589
Fitzwilliam Bennet-Darcy Avatar asked Aug 18 '16 16:08

Fitzwilliam Bennet-Darcy


People also ask

Why do we delete the copy constructor?

Copy constructor (and assignment) should be defined when ever the implicitly generated one violates any class invariant. It should be defined as deleted when it cannot be written in a way that wouldn't have undesirable or surprising behaviour.

Can a copy constructor be a template?

The copy constructor lets you create a new object from an existing one by initialization. A copy constructor of a class A is a non-template constructor in which the first parameter is of type A& , const A& , volatile A& , or const volatile A& , and the rest of its parameters (if there are any) have default values.

How does the c++ copy constructor work?

Copy Constructor in C++ Copy constructor is used to initialize the members of a newly created object by copying the members of an already existing object. Copy constructor takes a reference to an object of the same class as an argument.

How does a default constructor differ from other constructors?

A Default constructor is defined to have no arguments at all as opposed to a constructor in general which can have as many arguments as you wish.


2 Answers

The trouble here is that deleted functions still participate in overload resolution. So given

Foo<int> a;
Foo<int> b{a};

the viable functions are the deleted copy constructor and the template constructor with deduced template argument int. Being a non-template, the deleted copy constructor wins. And using the deleted function makes the program ill-formed.

So no, a template constructor cannot ever be instantiated as a copy constructor for copying an object of the same type.

like image 140
aschepler Avatar answered Sep 24 '22 18:09

aschepler


No it can't: overload resolution always considers non-templated functions first, and when a deleted one is encountered, overload resolution fails rather than a template overload being considered.

Allow me to introduce the default constructor into your class with the line

Foo() = default;

Then, consider two variables

Foo<double> double_foo;
Foo<int> int_foo;

Then note

  1. Foo<int> bar(double_foo); is allowed due to the template
  2. Foo<int> bar(int_foo); is not allowed due to the deleted constructor
  3. Foo<int> bar = Foo<int>(); would be allowed if you had re-introduced the move constructor by writing Foo(const Foo&&) = default;. You need to use the = syntax here since Foo<int> bar(Foo<int>()); is a forward declaration.

Finally, your assertion "the copy constructor must not be a template function" is not correct. Credit to @LightnessRacesInOrbit:

C++14 12.8.2 "A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).

like image 38
Bathsheba Avatar answered Sep 23 '22 18:09

Bathsheba