为什么非常量引用参数可以绑定到临时对象

Why can a non-const reference parameter be bound to a temporary object?

本文关键字:绑定 临时对象 参数 非常 常量 引用 为什么      更新时间:2023-10-16
char f1();
void f2(char&);
struct A {};
A    f3();
void f4(A&);
int main()
{
    f2(f1()); // error C2664. This is as expected.
    f4(f3()); // OK! Why???
}

错误 C2664:"void f4(char &)":无法从"char"转换参数 1 到"字符 &"

我被告知,在C++中,非常量引用参数不能绑定到临时对象;在上面的代码中,f2(f1());按预期触发错误。

但是,为什么相同的规则不适用于代码行f4(f3());

PS:我的编译器是VC++ 2013。即使我f2(f1());注释该行,也包含f4(f3());的代码将被编译而没有任何错误或警告。

更新:

MSDN 说:

在以前版本的 Visual C++ 中,非常量引用可以是 绑定到临时对象。现在,临时对象只能绑定 到常量引用。

所以我认为这是VC++的错误。我已向 VC++ 团队提交了错误报告

如果使用

/Za 选项进行编译以禁用语言扩展,编译器将拒绝这两个调用:

> cl /Za test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.
test.cpp
test.cpp(11): error C2664: 'void f2(char &)' : cannot convert argument 1 from 'char' to 'char &'
test.cpp(12): error C2664: 'void f4(A &)' : cannot convert argument 1 from 'A' to 'A &'
        A non-const reference may only be bound to an lvalue

在几种(非常受限的)情况下,启用语言扩展的编译器仍将允许非常量左值引用绑定到右值表达式。 我的理解是,这主要是为了避免破坏几个依赖这个"扩展"的巨大遗留代码库。

(通常,不建议使用/Za 的原因有很多,但主要是因为无法使用/Za 选项 #included Windows SDK 标头。

您的编译器不符合标准(也许这是记录的编译器扩展?GCC 给出以下错误:

main.cpp: In function 'int main()':
main.cpp:11:11: error: invalid initialization of non-const reference of type 'char&' from an rvalue of type 'char'
    f2(f1()); // error C2664. This is as expected.
        ^
main.cpp:2:6: error: in passing argument 1 of 'void f2(char&)'
void f2(char&);
    ^
main.cpp:12:12: error: invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A'
    f4(f3()); // OK! Why???
            ^
main.cpp:7:6: error: in passing argument 1 of 'void f4(A&)'
void f4(A&);
编译器选项/

permissive-(配置属性> C/C++> 所有选项>一致性模式)也禁用Microsoft语言扩展(根据 James McNellis 的答案),并将破坏不符合标准的代码。

此选项禁用宽松行为,并设置/Zc 编译器选项以实现严格一致性。

https://learn.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=msvc-160

作为参考,我使用的是Visual Studio 2019版本16.9.4并为v142平台工具集进行编译。