4

Case 1

The following code produces drastically different results in MSVC and GCC:

#include <iostream>

template <typename T>
void foo(const T&) {
#ifdef _MSC_VER
    std::cout << "foo(const T&): " << __FUNCDNAME__ << std::endl;
#else
    std::cout << __PRETTY_FUNCTION__ << std::endl;
#endif
}

void foo(const char*) {
    std::cout << "foo(const char*)" << std::endl;
}

int main() {
    extern char s[];
    foo(s);
}

char s[] = "abc";

MSVC 2013 Update 5, MSVC 2015 Update 1 (also tried Update 2 on http://webcompiler.cloudapp.net with the same result):

foo(const char*)

GCC 5.3.0, Clang 3.7.0 (DEMO):

void foo(const T&) [with T = char []]

Case 2

Now let's remove the templates:

#include <iostream>

void foo(const char(&)[]) {
    std::cout << "foo(const char(&)[])" << std::endl;
}

void foo(const char*) {
    std::cout << "foo(const char*)" << std::endl;
}

int main() {
    extern char s[];
    foo(s);
}

char s[] = "abc";

MSVC produces error:

error C2668: 'foo' : ambiguous call to overloaded function
could be 'void foo(const char *)'
or       'void foo(const char (&)[])'

GCC produces another error (with both -std=c++14 and -std=c++1z):

main.cpp:3:29: error: parameter '<anonymous>' includes reference to array of unknown bound 'const char []'
     void foo(const char(&)[]) {

And Clang compiles with both -std=c++14 and -std=c++1z and outputs:

foo(const char(&)[])

For the first case, in my opininon with C++14 the specialization void foo(const T&) [with T = char []] shouldn't have been produced in the first place, so MSVC is right. But in C++1z GCC and Clang are right.

For the second case, I think with C++14 GCC is right and with C++1z Clang is right.

(The important difference between C++14 and C++1z here is CWG 393)


So the questions are, which compiler is right in the first and the second cases in C++14 (N4140) and C++1z (N4567)?

And another question, which compiler(s), if any, should I file a bug for?

Anton Savin
  • 40,838
  • 8
  • 54
  • 90

1 Answers1

5

const char(&)[] is a valid parameter as of CWG 393; I filed the corresponding bug report for GCC just a week ago.

As for which of VC++ and Clang is correct, first see this answer; MSVC would be correct if s was declared const. However, because it wasn't, we have to perform both an array-to-pointer and qualification conversion in the char const* case - which makes the other SCS a subsequence of this one (Qualification Adjustment, as opposed to Lvalue Transformation, is not ignored!), i.e. Clang is correct in both cases.

Community
  • 1
  • 1
Columbo
  • 60,038
  • 8
  • 155
  • 203
  • But qualification conversion is performed in both cases, and moreover, the conversions are different (`char*` -> `char const*` and `char(&)[]` -> `char const(&)[]`), so how can one sequence be a subsequence of another? – Anton Savin Jan 25 '16 at 20:37
  • 1
    Qualification conversion solely happens for pointers. The array reference binds directly, and that's all that counts. – Columbo Jan 25 '16 at 20:43