3

I was trying to write a straightforward solution to this question: array decay to pointer and overload resolution

Clearly in the original, both overloads have equal conversion strength (exact match), so the non-template is preferred. Indeed, if I change the other to a template, the call become ambiguous:

struct stg
{
    template<typename T = void>
    stg(const char* const& c_str, T* = 0);

    template<int N>
    stg(const char (&str) [N]);
};

So I wanted to introduce a user-defined conversion, which would be strictly worse than the exact match of the second overload.

struct stg
{
    template<typename> struct cvt { operator int() { return 0;} };

    template<typename T = void>
    stg(const char* const& c_str, int = cvt<T>());

    template<int N>
    stg(const char (&str) [N]);
};

But g++ says this is still ambiguous. Why does the user-defined conversion in the default argument not affect overload ranking?

Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720

1 Answers1

4

[over.match.viable]/2 (from >n3797, github 5f7cb4)

First, to be a viable function, a candidate function shall have enough parameters to agree in number with the arguments in the list.

  • If there are m arguments in the list, all candidate functions having exactly m parameters are viable.

  • A candidate function having fewer than m parameters is viable only if it has an ellipsis in its parameter list (8.3.5). For the purposes of overload resolution, any argument for which there is no corresponding parameter is considered to “match the ellipsis” (13.3.3.1.3).

  • A candidate function having more than m parameters is viable only if the (m+1)-st parameter has a default argument (8.3.6). For the purposes of overload resolution, the parameter list is truncated on the right, so that there are exactly m parameters.

[emphasis mine]

dyp
  • 38,334
  • 13
  • 112
  • 177