gpt4 book ai didi

c++ - 在 gcc 中意外调用了 const 重载。编译器错误或兼容性修复?

转载 作者:行者123 更新时间:2023-12-01 12:30:30 27 4
gpt4 key购买 nike

我们有一个更大的应用程序,它依赖于 char 和 const char 数组的模板重载。在 gcc 7.5、clang 和 Visual Studio 中,下面的代码在所有情况下都打印“NON-CONST”。但是,对于 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();
}

gcc 8 和 9 输出(来自 Godbolt)是:
CONST test_1
NON-CONST test_2
NON-CONST test_3
NON-CONST test_4
NON-CONST test_5

在我看来,这似乎是一个编译器错误,但我想这可能是与语言更改相关的其他问题。有人确切知道吗?

最佳答案

当您从函数(指定函数本地对象)返回纯 id 表达式时,编译器被要求执行两次重载解析。首先,它把它当作一个右值,而不是一个左值。只有当第一次重载解析失败时,才会以对象作为左值再次执行。

[class.copy.elision]

3 In the following copy-initialization contexts, a move operation might be used instead of a copy operation:

  • If the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or

  • ...

overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.  — end note ]



如果我们要添加一个右值重载,
template <size_t N>
MyClass (char (&&value)[N])
{
std::cout << "RVALUE " << value << '\n';
}

输出将变为
RVALUE test_1
NON-CONST test_2
NON-CONST test_3
NON-CONST test_4
NON-CONST test_5

这是正确的。如您所见,不正确的是 GCC 的行为。它认为第一个重载决议是成功的。这是因为 const 左值引用可能绑定(bind)到右值。但是,它会忽略文本 “或者如果所选构造函数的第一个参数的类型不是对对象类型的右值引用” .据此,它必须丢弃第一次重载决议的结果,然后再做一次。

好吧,无论如何,这就是 C++17 的情况。当前的标准草案有不同的说法。

If the first overload resolution fails or was not performed, overload resolution is performed again, considering the expression or operand as an lvalue.



删除了 C++17 之前的文本。所以这是一个时间旅行的错误。 GCC 实现了 C++20 的行为,但即使标准是 C++17 也是如此。

关于c++ - 在 gcc 中意外调用了 const 重载。编译器错误或兼容性修复?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59938540/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com