不同编译器的奇怪行为,引用未知范围的数组

时间:2016-01-25 20:05:11

标签: c++ visual-c++ g++ clang++ c++17

案例1

以下代码在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上尝试了更新2,结果相同):

foo(const char*)

GCC 5.3.0,Clang 3.7.0(DEMO):

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

案例2

现在让我们删除模板:

#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)中的第一个和第二个案例中是正确的?

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

1 个答案:

答案 0 :(得分:5)

截至CWG 393,

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

至于VC ++和Clang中哪一个是正确的,首先看this answer;如果s被声明为const,则MSVC 正确无误。但是,因为它不是,我们必须在char const*情况下执行数组到指针和限定转换 - 这使得另一个SCS成为这个的后续序列(资格调整,而不是左值变换,不会被忽略!),即Clang在两种情况下都是正确的。