在以下代码中,main()
中的局部变量rcc
和foo()
中的参数r
具有相同的类型const CC&
。成功地为局部变量赋值了字符串文本,而将字符串文本传递给foo()
则编译失败。为什么相同类型会有不同的行为?
注意:在Visual Studio 2019中编译
typedef char CC[5];
void foo(const CC& r)
{
std::cout << r << std::endl;
}
void bar(const char(&r)[])
{
std::cout << r << std::endl;
}
int main()
{
const CC &rcc = "ex"; // Pass compilation with all standards
const char(&rchar)[] = "ex"; // Pass compilation with all standards
std::cout << rcc << ' ' << rchar << std::endl;
bar("ex"); // Pass compilation with ISO C++20 standard only
foo("ex"); // Fails compilation with all standards
return 0;
}
我尝试将字符串文本传递给参数类型为const T&
的函数,其中T
是char[]
的typedef。
我期望对函数参数赋值的行为与对相同类型的局部变量赋值的行为相同。
我收到以下编译错误:
error C2664: 'void foo(const CC (&))': cannot convert argument 1 from 'const char [3]' to 'const CC (&)'
message : Reason: cannot convert from 'const char [3]' to 'const CC'
message : There is no context in which this conversion is possible
message : see declaration of 'foo'
1条答案
按热度按时间bjp0bcyl1#
bar("ex");
自C20以来就是良构的,因为C20允许隐式地删除指针/引用到数组的数组边界(参见https://github.com/cplusplus/papers/issues/565及其参考文献)。因此
bar
的参数自C++20起将直接绑定到字符串字面量。我认为
const CC &rcc = "ex";
应该可以工作,因为应用的初始化规则链中的第一项是[dcl.init.ref]/5.4.2,根据该规则,引用被绑定到从目标类型的纯右值实现的临时值,而没有引用限定符,该限定符被隐式地从初始化表达式转换为。“* 隐式转换 *”在[conv.general]/3中定义为等效于来自原始初始化表达式的虚变量
t
的声明,在本例中为这种初始化是格式良好的,因为从字符串常量初始化字符数组的规则允许在零初始化的数组中保留额外的空间,请参见[dcl.init.string]/3。
因此,
rcc
将绑定到一个临时的(且生存期延长的)const char[5]
数组,该数组初始化为字节序列e
、x
、\0
、\0
、\0
。我认为
foo("ex");
也应该没有区别。但是我不能完全确定这是预期的解释。GCC和Clang都不接受
const CC &rcc = "ex";
,我认为[conv.general]/3有一些问题。