如何以逐参数方式通过非模板函数实现完美转发?
实现带类型约束的完美转发方案
先看你的问题代码:
template<typename T> class Group; template<typename...U> class Group<std::tuple<U...>> { public: typedef std::tuple<U...> type; void emplace_back(U&...elem) { data_.emplace_back(elem...); } void emplace_back(U&&...elem) { data_.emplace_back(elem...); } private: std::vector<type> data_; }; int main() { Group<std::tuple<int, std::string>> g; int e1 = 10; std::string e2 = "elem2"; g.emplace_back(e1, e2); //OK g.emplace_back(e1, "elem2"); //error, no instance of overloaded function return 0; }
问题根源在于你重载的两个emplace_back只能统一接收左值引用或右值引用参数,无法混合处理不同值类别的参数,导致左值+右值的组合调用无法匹配。
要解决这个问题,你可以把emplace_back改成模板函数,同时通过类型约束保留原类模板参数U...的类型限制,既实现完美转发,又不会允许任意类型传入:
C++20 版本(推荐)
利用requires表达式直接约束参数类型:
template<typename T> class Group; template<typename...U> class Group<std::tuple<U...>> { public: using type = std::tuple<U...>; // 约束每个参数Args能构造对应的U类型,同时完美转发 template<typename...Args> requires (std::is_constructible_v<U, Args> && ...) void emplace_back(Args&&...elem) { data_.emplace_back(std::forward<Args>(elem)...); } private: std::vector<type> data_; };
C++17 版本
如果使用C++17,可以用std::enable_if实现同样的约束:
#include <type_traits> template<typename T> class Group; template<typename...U> class Group<std::tuple<U...>> { public: using type = std::tuple<U...>; template<typename...Args, // 用enable_if启用模板的条件:所有Args都能构造对应的U std::enable_if_t<(std::is_constructible_v<U, Args> && ...), int> = 0> void emplace_back(Args&&...elem) { data_.emplace_back(std::forward<Args>(elem)...); } private: std::vector<type> data_; };
效果说明
- 完美转发:通过
std::forward<Args>(elem),每个参数会按自身的左值/右值属性转发给std::vector::emplace_back,解决了混合值类别参数的问题。 - 类型约束:
requires或enable_if确保每个传入的参数都能构造对应的U类型,和你原来的非模板函数一样,不会接受不符合U...类型要求的参数。
测试你的示例代码,两个emplace_back调用都能正常编译运行:
int main() { Group<std::tuple<int, std::string>> g; int e1 = 10; std::string e2 = "elem2"; g.emplace_back(e1, e2); // 左值参数正常转发 g.emplace_back(e1, "elem2"); // 右值字符串字面量正常转发,可构造std::string return 0; }
内容的提问来源于stack exchange,提问作者soyokaze
相关产品推荐
相关产品推荐

