C++非模板转发函数无法运行,与完美转发模板的核心差异是什么
关于C++完美转发的疑问解答
1. 为什么非模板实现的fwd_func会报错?
你写的void fwd_func(big_class &&bc)中,big_class&&是固定类型的右值引用,C++语法规定右值引用只能绑定到右值(临时对象、std::move转化后的左值等)。你在main中传入的bc是栈上的具名变量,属于左值,自然无法绑定到右值引用参数,因此直接触发编译错误。
2. 非模板版本和模板完美转发版本的核心区别
二者的核心差异在于是否触发转发引用(万能引用)的类型推导和引用折叠规则:
- 只有当
&&符号出现在待推导的模板参数后面时,才属于转发引用,会触发特殊的类型推导逻辑:- 传入左值参数时,模板参数T会被推导为「左值引用类型」,比如你传左值
big_class变量,T会被推导为big_class&,此时T&&会触发引用折叠:big_class& &&折叠为big_class&,可以正常接收左值 - 传入右值参数时,模板参数T会被推导为原始类型
big_class,此时T&&就是big_class&&,可以正常接收右值
- 传入左值参数时,模板参数T会被推导为「左值引用类型」,比如你传左值
- 非模板版本没有模板参数推导的过程,
big_class&&就是固定的右值引用,没有引用折叠的步骤,因此只能接收右值,完全没有转发的能力。std::forward本身也是依赖模板推导出来的T类型来保留参数原本的值类别,没有正确的T推导结果,std::forward也无法正常工作。
3. 只传递big_class类型时的最优选择
分场景判断:
- 如果你的下游函数
func只需要读取参数、不会修改参数也不需要转移参数的所有权,直接用const big_class&传递是最优选择:左值、右值都可以正常接收,没有多余的拷贝开销,也不需要写复杂的完美转发逻辑。 - 如果后续需要修改参数、或者要转移参数的所有权(比如要移动构造新对象、传给需要拿走所有权的接口),又不想写左值、右值两个重载,才需要考虑用模板完美转发,或者根据实际开销选择按值传递+移动的方案。
内容的提问来源于stack exchange,提问作者code_fodder
相关产品推荐
相关产品推荐

