不同编译器引用未知边界数组的奇怪行为
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 在两种情况下都是正确的。
案例一
以下代码在 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 在两种情况下都是正确的。