C++模板引用类型匹配报错:无法绑定右值到非const左值引用
关于C++引用折叠导致的绑定错误解析
问题代码
#include <iostream> using namespace std; class M { public: M(): a(0), b(0) {} M(int a, int b): a(a), b(b) {} private: int a; int b; }; template <typename T> class Test { public: Test(const T& my) { } T my_; }; template <typename T> using ReferTest = Test<T&>; int main() { ReferTest<M> t2(M(3,4)); }
错误信息
main.cpp: In function ‘int main()’: main.cpp:25:20: error: cannot bind non-const lvalue reference of type ‘M&’ to an rvalue of type ‘M’ 25 | ReferTest<M> t2(M(3,4)); | ^~~~~~ main.cpp:16:17: note: initializing argument 1 of ‘Test<T>::Test(const T&) [with T = M&]’ 16 | Test(const T& my) { } | ~~~~~~~~~^~
问题解析
核心原因:引用折叠规则
你看到构造函数写的是const T&,但实际推导后变成了非const左值引用,问题出在C++的引用折叠规则:
当ReferTest<M>展开为Test<M&>时,Test的模板参数T是M&。此时构造函数的参数const T&会被替换为const (M&)&——但C++不允许“引用的引用”,会按照规则自动折叠:
- 所有包含左值引用的引用组合(比如
T& &、T& &&)都会折叠成T& - 只有纯右值引用的组合
T&& &&会折叠成T&&
这里的const (M&)&中,const是试图修饰M&这个引用类型,但引用本身无法被const修饰(引用一旦绑定就不能更改指向,const引用的本质是指向const对象的引用),因此这个const修饰会被忽略,最终折叠后的参数类型就是M&——也就是非const的左值引用。
为什么会报错?
非const左值引用M&只能绑定到左值,而M(3,4)是临时对象(右值),不符合绑定规则,因此编译器抛出错误。
解决方法
可以根据需求选择以下方案:
- 方案1:修改别名模板,让Test的参数为
const T&而非T&:template <typename T> using ReferTest = Test<const T&>; - 方案2:将临时对象转为左值,比如存储到变量中:
M obj(3,4); ReferTest<M> t2(obj); - 方案3:调整Test的构造函数参数,直接使用
T(当T是引用时,效果等价于传递引用):template <typename T> class Test { public: Test(T my) { } T my_; };
内容的提问来源于stack exchange,提问作者wenxi wang
相关产品推荐
相关产品推荐

