This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-11-11


2377. Explicit copy constructor vs function viability

Section: 12.2.3  [over.match.viable]     Status: NAD     Submitter: Xiang Fan     Date: 2018-06-05

According to 12.2.3 [over.match.viable] paragraph 4,

Third, for F to be a viable function, there shall exist for each argument an implicit conversion sequence (12.2.4.2 [over.best.ics]) that converts that argument to the corresponding parameter of F. If the parameter has reference type, the implicit conversion sequence includes the operation of binding the reference, and the fact that an lvalue reference to non-const cannot be bound to an rvalue and that an rvalue reference cannot be bound to an lvalue can affect the viability of the function (see 12.2.4.2.5 [over.ics.ref]).

The description of an implicit conversion sequence in 12.2.4.2 [over.best.ics] paragraph 6 only discusses the relationship of the types. For example, for a class type, it says,

When the parameter has a class type and the argument expression has the same type, the implicit conversion sequence is an identity conversion.

This ignores whether the conversion can actually be performed, considering explicit qualification of constructors and conversion functions. There is implementation divergence in the handling of an example like:

  template<typename T> void f(T);
  template<typename T> void f(const T &);

  struct Woof {
    explicit Woof() = default;
    explicit Woof(const Woof&) = default;
    explicit Woof(Woof&&) = default;
    Woof& operator=(const Woof&) = default;
    Woof& operator=(Woof&&) = default;
  };

  int main() {
    const Woof cw{};
    f(cw);
  }

If f(Woof) is viable, the call is ambiguous, even though calling f(Woof) would be ill-formed because of the explicit copy constructor.

This seems to be consistent with the general approach described in 12.2.4.2 [over.best.ics] paragraph 2, even though explicitness is not explicitly mentioned:

Implicit conversion sequences are concerned only with the type, cv-qualification, and value category of the argument and how these are converted to match the corresponding properties of the parameter. Other properties, such as the lifetime, storage class, alignment, accessibility of the argument, whether the argument is a bit-field, and whether a function is deleted (9.5.3 [dcl.fct.def.delete]), are ignored. So, although an implicit conversion sequence can be defined for a given argument-parameter pair, the conversion from the argument to the parameter might still be ill-formed in the final analysis.

Rationale (November, 2018):

The intent is that the example should be ambiguous. As an editorial matter, the “such as” and “so” remarks should be turned into notes.