如何对类模板参数使用std::forward 解决右值引用传参编译错误
错误原因
*转发引用(也叫万能引用)*和普通右值引用的适用场景有明确区别:
- 仅当参数为函数自身模板参数的
T&&类型时,才属于转发引用,会根据传入参数的值类型自动推导模板参数,触发引用折叠规则,可同时绑定左值和右值。你代码里的print函数符合这个要求,因此传左值data不会报错。 - 类的成员函数
add_to_list里的T是类模板的参数,在你实例化Data_List<std::vector<int>>时,T就已经固定为std::vector<int>,此时函数参数T&&就是普通的右值引用,只能绑定右值,你传入左值变量data自然会触发类型绑定错误。
正确实现方案
方案1:成员函数模板+转发引用
将add_to_list改为自带模板参数的成员函数,用函数自身的模板参数做转发,修改后的代码如下:
template<typename T> class Data_List { std::vector<T> data_list; public: Data_List() = default; ~Data_List() = default; std::size_t get_list_size() { return data_list.size(); } // 修改为成员函数模板,使用自身的模板参数U做转发 template<typename U> void add_to_list(U&& data) { std::cout << "before inside add_to_list: " << data.size() << std::endl; data_list.push_back(std::forward<U>(data)); std::cout << "after inside add_to_list: " << data.size() << std::endl; } };
修改后不管传入左值还是右值都可以正常编译运行,完美保留参数的值类型。
方案2:重载左值/右值版本
如果不想使用成员模板,也可以分别重载两个版本的add_to_list,分别处理左值和右值参数:
// 处理左值参数的版本 void add_to_list(const T& data) { std::cout << "before inside add_to_list: " << data.size() << std::endl; data_list.push_back(data); std::cout << "after inside add_to_list: " << data.size() << std::endl; } // 处理右值参数的版本 void add_to_list(T&& data) { std::cout << "before inside add_to_list: " << data.size() << std::endl; data_list.push_back(std::move(data)); std::cout << "after inside add_to_list: " << data.size() << std::endl; }
这种写法效果和完美转发一致,也可以同时支持左值和右值传入。
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

