Question Details

No question body available.

Tags

c++ arrays overload-resolution

Answers (2)

Accepted Answer Available
Accepted Answer
February 28, 2026 Score: 2 Rep: 18,913 Quality: High Completeness: 60%

the type of N in T[N] is std::sizet.

True, which means the two overloads have to be ambiguous.

Think about the implications of this requirement. Every time an array is declared, there is an implicit conversion of the size to std::sizet. It is as if each valid T[N] is replaced by T[staticcast(N)], with emphasis on "valid". (If compilation fails without this replacement, the replacement is not done. For example, using a scoped enumeration (enum class) as the size will not compile even though adding the cast would make it compile.) For the question's code, this replacement preserves semantics.

Take another look at the declaration of the last template:

template
void check(char const (&)[N])

What is the type of the parameter? It is a reference to an array. Since it is an array, the size must be of type std::sizet, as you yourself pointed out. The compiler sees this declaration as

template
void check(char const (&)[staticcast(N)])

This conversion is done before overload resolution sees the function signature. The type of this parameter is the same as the type of the parameter to the other template. Ambiguous.

Note that the same implicit conversion happens in the declaration char c[5], as your first example shows. The literal 5 has type int and gets converted to std::sizet in order to form the type more accurately written char [5uz] (typically char [5ull] pre-C++23). Whenever you see an array type, the size must be std::size_t regardless of the nominal type of the expression giving the size.

February 28, 2026 Score: 4 Rep: 229,699 Quality: Medium Completeness: 100%

Both overloads are viable.

Then we have to select the Best viable function

Your concern should be:

  1. there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2, or, if not that,

Then in Ranking of implicit conversion sequences

  1. Exact match: no conversion required, lvalue-to-rvalue conversion, qualification conversion, function pointer conversion,(since C++17) user-defined conversion of class type to the same class
  2. Promotion: integral promotion, floating-point promotion
  3. Conversion: integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base

I don't see anything which won't qualify const char(&)[N] (with N either std::sizet nor int) as exact match.

And there are no other tie breaker.

So it is ambiguous.

As a note, they both have same signature, see:

template void check(char const (&)[N]) {}
template void checkint(char const (&)[N]) {}

staticassert(std::issame_v); // Pass

Demo

You might also note that conversion ranking concerns function parameters, not conversion to template parameter.

template void ambiguous() {}
template void ambiguous() {}

int main() { constexpr int n = 5; ambiguous(); // Error constexpr int sz = 42; ambiguous(); // Error }

Demo