You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以逐参数方式通过非模板函数实现完美转发?

实现带类型约束的完美转发方案

先看你的问题代码:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 03:12:46