Note; gcc
and clang
shows the correct behavior when trying to compile the provided snippet.
Why is vc++
wrong to accept the snippet?
A function template can never be instantiated in a way that produces a copy-constructor, as can be read in the two following quotes from the c++ standard:
[class.copy]
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).
...
6) A declaration of a constructor for class X
is ill-formed if its first parameter is of type (optionally cv-qualified) X
and either there are no other parameters or else all other parameters have default arguments. A member function template is never instantiated to produce such a constructor signature.
If a move-constructor is explicitly declared the implicitly generated copy-constructor won't be callable, see the following:
[class.copy]
7) If a 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)
struct Obj {
template<typename T>
Obj (T const&) { }
Obj (Obj&&) { }
};
...
Obj a;
Obj b (a);
Having the previously mentioned quotes from the c++ standard in mind we can easily see that the above definition of Obj
would be semantically equivalent of the below since our explicitly declared move-constructor will make our implicitly declared copy-constructor = delete;
.
struct Obj {
template<typename T>
Obj (T const&) { }
Obj (Obj const&) = delete;
Obj (Obj&&) { }
};
According to the rules of overload resolution deleted functions still participate when trying to find the best match, but if they win the battle of having the best fit the program is ill-formed. This is exactly what is happening in the snippet.
Obj (Obj const&) = delete
is a better fit than template<typename T> Obj (T const&)
, but since the copy-constructor isn't callable the snippet fails to compile.