【问题标题】:Odd behavior of different compilers with references to array of unknown bound引用未知边界数组的不同编译器的奇怪行为
【发布时间】:2016-01-25 20:05:11
【问题描述】:

案例 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 更新 5、MSVC 2015 更新 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&amp;) [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(&amp;)[] ???
  • 如果您将s 设为const char[],您将在所有三个编译器中收到类似的错误消息
  • @melak47 这就是重点,在这里将资格转换为const 很重要。

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


【解决方案1】:

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

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

【讨论】:

  • 但是两种情况都进行了资格转换,而且转换的方式也不一样(char* -> char const*char(&amp;)[] -> char const(&amp;)[]),那么怎么可能是一个序列另一个的子序列?
  • 限定转换只发生在指针上。数组引用直接绑定,仅此而已。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-27
  • 2019-05-22
  • 1970-01-01
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多