Rob*_*b L 8 c++ gcc overloading language-lawyer compiler-bug
我们有一个更大的应用程序,它依赖于 char 和 const char 数组的模板重载。在 gcc 7.5、clang 和 Visual Studio 中,下面的代码在所有情况下都会打印“非常量”。但是,对于 gcc 8.1 及更高版本,输出如下所示:
#include <iostream>
class MyClass
{
public:
template <size_t N>
MyClass(const char (&value)[N])
{
std::cout << "CONST " << value << '\n';
}
template <size_t N>
MyClass(char (&value)[N])
{
std::cout << "NON-CONST " << value << '\n';
}
};
MyClass test_1()
{
char buf[30] = "test_1";
return buf;
}
MyClass test_2()
{
char buf[30] = "test_2";
return {buf};
}
void test_3()
{
char buf[30] = "test_3";
MyClass x{buf};
}
void test_4()
{
char buf[30] = "test_4";
MyClass x(buf);
}
void test_5()
{
char buf[30] = "test_5";
MyClass x = buf;
}
int main()
{
test_1();
test_2();
test_3();
test_4();
test_5();
}
Run Code Online (Sandbox Code Playgroud)
gcc 8 和 9 输出(来自 Godbolt)是:
CONST test_1
NON-CONST test_2
NON-CONST test_3
NON-CONST test_4
NON-CONST test_5
Run Code Online (Sandbox Code Playgroud)
这在我看来是一个编译器错误,但我想这可能是与语言更改相关的其他问题。有人确切知道吗?
当您从一个函数(指定一个函数本地对象)返回一个普通的 id 表达式时,编译器被强制执行两次重载解析。首先,它把它当作一个右值,而不是一个左值。只有在第一次重载决议失败时,才会以对象作为左值再次执行。
[class.copy.elision]
3在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:
如果 return 语句中的表达式是一个(可能带括号的)id 表达式,它命名一个对象,该对象具有在最内部封闭函数或 lambda 表达式的主体或参数声明子句中声明的自动存储持续时间,或
...
为副本选择构造函数的重载决议首先执行,就好像对象是由右值指定的一样。如果第一次重载决议失败或没有执行,或者如果所选构造函数的第一个参数的类型不是对对象类型的右值引用(可能是 cv 限定的),则再次执行重载决议,将对象视为左值。[?注:无论是否发生复制省略,都必须执行此两阶段重载决议。如果不执行省略,它确定要调用的构造函数,并且即使调用被省略,所选的构造函数也必须是可访问的。?—?尾注?]
如果我们要添加一个右值重载,
template <size_t N>
MyClass (char (&&value)[N])
{
std::cout << "RVALUE " << value << '\n';
}
Run Code Online (Sandbox Code Playgroud)
输出将变成
RVALUE test_1
NON-CONST test_2
NON-CONST test_3
NON-CONST test_4
NON-CONST test_5
Run Code Online (Sandbox Code Playgroud)
这是正确的。正如您所见,GCC 的行为是不正确的。它认为第一个重载决议是成功的。那是因为 const 左值引用可能绑定到右值。但是,它会忽略文本“或者如果所选构造函数的第一个参数的类型不是对对象类型的右值引用”。据此,它必须丢弃第一次重载决议的结果,然后再做一次。
好吧,无论如何,这就是 C++17 的情况。当前的标准草案说了一些不同的东西。
如果第一次重载决议失败或未执行,则再次执行重载决议,将表达式或操作数视为左值。
删除了 C++17 之前的文本。所以这是一个时间旅行错误。GCC 实现了 C++20 行为,但即使标准是 C++17,它也会这样做。
| 归档时间: |
|
| 查看次数: |
186 次 |
| 最近记录: |