C++20传递临时构造对象作为参数报错?原因及批量修复方案
报错核心原因
你遇到的不是C20标准新增的限制,而是**Visual Studio在C20模式下默认关闭了一个历史非标准扩展**。
C标准从C98开始就明确规定:临时对象(比如Foo(3)这种匿名对象)只能绑定到const左值引用或右值引用,不能直接绑定到非const左值引用。但早年MSVC为了方便旧代码编写,加入了一个非标准扩展——允许临时对象绑定到非const左值引用。在C20之前,这个扩展默认开启;C20开始,MSVC默认启用严格标准符合性,关闭了该扩展,所以原本依赖这个特性的代码就会报错。
批量修复方案
根据代码的实际需求,可以选择以下几种修复方式:
1. 修改函数参数为const引用(推荐)
如果函数不需要修改传入的对象,直接将参数类型改为const T&,这是最符合C标准的写法,兼容所有C版本:
// 原代码 void bar(Foo& f) { ... } // 修改后 void bar(const Foo& f) { ... }
对应你的readText场景:
void readText(const TextReader& r) { ... }
2. 修改函数参数为右值引用
如果函数需要修改临时对象(场景较少),可以将参数改为右值引用T&&,临时对象可以合法绑定到右值引用:
void bar(Foo&& f) { ... }
3. 显式创建左值变量
不想修改函数签名的话,可以先把临时对象存储为一个具名变量,再传递给函数:
// 原代码 bar(Foo(3)); // 修改后 Foo temp(3); bar(temp);
对应你的readText场景:
FileDataSource d("file.text"); TextReader reader(d); readText(reader);
4. 强制启用MSVC的非标准扩展(不推荐)
如果需要快速兼容旧代码,可在项目编译设置中添加/Zc:referenceBinding-选项,强制允许临时对象绑定非const左值引用。但这种方式不符合C++标准,后续编译器版本可能移除支持,仅作为临时过渡方案。
为什么C++20要“收紧”这个行为?
严格来说这不是C20移除特性,而是**MSVC终于默认遵循了C标准的原有规定**。临时对象绑定非const左值引用的行为本身就属于未定义行为的灰色地带:虽然在函数调用期间临时对象的生命周期会被延长,但这种写法容易误导开发者产生“可以长期持有这个引用”的错误认知,进而导致悬空引用等严重问题。C++20收紧标准符合性,是为了减少潜在的bug,让代码更健壮、更符合跨平台的标准规范。
内容的提问来源于stack exchange,提问作者Chifti Saidi

