C++临时值模板类型推导疑问:wrapper(A())为何编译报错?
为什么
wrapper(A())会触发非const左值引用绑定右值的错误? 先看你的代码:
#include <iostream> #include <vector> using namespace std; template <typename T> void wrapper(T& u) { g(u); } class A {}; void g(const A& a) {} int main() { const A ca; wrapper(ca); // 正常编译 wrapper(A()); // 报错:cannot bind non-const lvalue reference of type 'A&' to an rvalue of type 'A' }
咱们一步步拆解两种调用的模板推导逻辑:
1. 调用wrapper(ca)的情况
ca是const A类型的左值。当编译器处理这个调用时,它需要推导模板参数T的类型,使得T&能匹配传入的实参类型。
因为实参是const A左值,编译器会把T推导为const A,这样函数参数就变成了const A&——完全匹配实参的类型,所以可以正常绑定,后续g(u)也能匹配到void g(const A&)。
2. 调用wrapper(A())的情况
A()是一个临时对象(右值)。这时候问题来了:你的模板函数参数是T&——也就是非const的左值引用。
C++的规则里,非const左值引用是不能绑定到右值的,这是为了防止意外修改临时对象(毕竟临时对象用完就销毁了,修改它没意义还容易出问题)。
那你可能会问:为什么编译器不把T推导为const A,让参数变成const A&来绑定右值?
这是模板类型推导的规则决定的:当函数参数是T&(非const左值引用)时,编译器只会考虑把T推导为能让T&绑定左值的类型。对于右值来说,没有办法让T&(非const)绑定它,所以推导直接失败,不会自动给T加上const来“凑”出const T&。
如果想要让wrapper既能接受左值也能接受右值,你有两种解决办法:
- 把模板参数改成
const T&:这样不管左值右值都能绑定,编译器会自动推导T为A,参数变成const A&,完美匹配g的参数。template <typename T> void wrapper(const T& u) { g(u); } - 或者使用万能引用
T&&,利用引用折叠规则来适配左值和右值:template <typename T> void wrapper(T&& u) { g(u); }
这样修改后,wrapper(A())就能正常编译了。
内容的提问来源于stack exchange,提问作者Jaebum
相关产品推荐
相关产品推荐

