不同编译器引用未知边界数组的奇怪行为

Odd behavior of different compilers with references to array of unknown bound

案例一

以下代码在 MSVC 和 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(也在 http://webcompiler.cloudapp.net 上尝试了 Update 2,结果相同):

foo(const char*)

GCC 5.3.0,Clang 3.7.0 (DEMO):

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

案例二

现在让我们删除模板:

#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 产生错误:

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

GCC 产生另一个错误(-std=c++14-std=c++1z):

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

并且 Clang 使用 -std=c++14-std=c++1z 进行编译并输出:

foo(const char(&)[])

对于第一种情况,根据我对 C++14 的看法,专业化 void foo(const T&) [with T = char []] 一开始就不应该产生,所以 MSVC 是正确的。但在 C++1z 中,GCC 和 Clang 是正确的。

对于第二种情况,我认为使用 C++14 GCC 是正确的,使用 C++1z Clang 是正确的。

(这里C++14和C++1z的重要区别是CWG 393


所以问题是,在 C++14 (N4140) 和 C++1z (N4567) 的第一种情况和第二种情况下哪个编译器是正确的?

另一个问题,我应该为哪个编译器(如果有)提交错误?

const char(&)[] 是 CWG 393 的有效参数;我一周前为 GCC 提交了相应的 bug report

至于VC++和Clang哪个正确,先看;如果 s 被声明为 const,则 MSVC 是正确的。然而,因为它不是,我们必须在 char const* 情况下同时执行 array-to-pointer 和 限定转换 - 这使得另一个 SCS 成为这个的子序列一个(资格调整,与左值转换相反,不被忽略!),即 Clang 在两种情况下都是正确的。