cplusplus / CWG

Core Working Group
23 stars 7 forks source link

CWG2837 [class.copy.ctor] Issues with by-value copy constructors #474

Open t3nsor opened 7 months ago

t3nsor commented 7 months ago

Full name of submitter: Brian Bi

Reference (section label): [class.copy.ctor], [namespace.udecl]

Issue description: [class.copy.ctor]/5 states:

A declaration of a constructor for a class X is ill-formed if its first parameter is of type cv 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.

This wording does not explain what happens if such a constructor signature is inherited from a base class; MSVC currently treats the using-declaration as ill-formed (https://godbolt.org/z/6x47rf4vT). We should say that such a constructor is excluded from the inherited set.

Also, the wording "never instantiated" doesn't explain at what step of the process instantiation stops. I doubt there would be any implementation divergence, but even still, we should be a bit more explicit and say the result is a substitution failure.

Suggested resolution:

Add a paragraph before [namespace.udecl]/13:

The set of declarations named by a using-declarator that inhabits a class C does not include any constructor whose first parameter has type cv C and all of whose remaining parameters (possibly none) have default arguments.

Edit [class.copy.ctor]/5:

A declaration of a constructor for a class X is ill-formed if its first parameter is of type 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.~ During type deduction for a constructor template of X ([temp.deduct.general]), if substitution produces such a constructor signature, type deduction fails.

In Example 5 to [class.copy.ctor]/5, edit the comment:

// ~does not instantiate the member template to produce S​::​S<S>(S);~ no S::S<S>(S) candidate generated from the member template;
// ~uses~ the implicitly declared copy constructor is used

jensmaurer commented 6 months ago

CWG2837

t3nsor commented 6 months ago

Oh, I also noticed that Clang has something like this in its testsuite:

template <class T, class U>
struct X {
    X() = default;
    X(X<T, T>);
};
int main() {
    X<int, int> x;
}

EDG, GCC, and MSVC all reject due to the current [class.copy.ctor]/5. Clang accepts and (I believe) simply treats X<int,int>::X(X<int, int>) as excluded from overload resolution. We might want to consider whether we want the Clang behavior in this case.

hubert-reinterpretcast commented 3 weeks ago

During type deduction for a constructor template of X ([temp.deduct.general]), if substitution produces such a constructor signature, type deduction fails.

That proposed wording is still wrong: A signature does not include default arguments. Also, (except for MSVC) implementations do not reject instantiating such constructor specializations for uses where the argument list has more than one argument (and that is probably the right thing).

https://godbolt.org/z/48Ghsoebc

struct A {
  template <typename T> A(T, int = 0);
  A(const A &) = default;
  A() = default;
};

A a(A{}, 42);  // OK