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

如何实现模板参数包展开的「复制」操作?

模板参数包展开的「复制」操作实现方法

嘿,关于模板参数包展开的「复制」操作,其实主要分两种常见场景:一种是在模板参数层面复制整个参数包或逐个元素,另一种是在运行时对参数包的元素执行复制操作。下面我给你详细讲讲每种场景的实现方式~

一、模板参数层面的参数包复制

这种场景是指我们要在模板类型/值的层面,生成重复的参数序列,比如把int, string变成int, string, int, string,或者每个元素重复两次变成int, int, string, string。

1. 复制整个参数包

如果只是想把整个参数包完整复制一遍,用C++17的折叠表达式就能很轻松实现。比如我们写一个函数,把传入的参数打印两次:

#include <iostream>

template<typename... Args>
void print_twice(Args&&... args) {
    // 第一次打印参数包
    (std::cout << ... << args) << '\n';
    // 第二次复制展开参数包再打印
    (std::cout << ... << args) << '\n';
}

int main() {
    print_twice(1, "hello", 3.14);
    // 输出:
    // 1hello3.14
    // 1hello3.14
}

如果要在模板类型里复制参数包(比如生成包含两份相同类型的tuple),可以借助一个辅助的拼接模板:

#include <tuple>

// 辅助函数,用于拼接两个tuple的参数包
template<typename... Args1, typename... Args2>
auto concat_pack(std::tuple<Args1...>, std::tuple<Args2...>) -> std::tuple<Args1..., Args2...>;

// 定义一个别名,把同一个参数包拼接两次
template<typename... Args>
using doubled_tuple = decltype(concat_pack(std::tuple<Args...>{}, std::tuple<Args...>{}));

// 使用示例
doubled_tuple<int, std::string> t = {1, "test", 2, "copy"};
// t的类型是std::tuple<int, std::string, int, std::string>

2. 逐个复制参数包元素

如果需要把参数包里的每个元素都重复N次(比如每个元素复制两次),可以用递归模板或者C++17的折叠表达式来实现:

运行时逐个复制到容器

用折叠表达式可以很简洁地把每个元素复制后插入容器:

#include <vector>

template<typename T, typename... Args>
std::vector<T> repeat_each_element(Args&&... args) {
    std::vector<T> vec;
    // 对每个参数执行两次push_back,实现复制
    ((vec.push_back(args), vec.push_back(args)), ...);
    return vec;
}

// 使用示例
auto vec = repeat_each_element<int>(1, 2, 3);
// vec的内容是 [1, 1, 2, 2, 3, 3]

模板类型层面逐个重复

如果要在类型层面实现每个元素重复,需要用递归模板来展开:

#include <tuple>

// 辅助模板:向tuple头部添加元素
template<typename... Args, typename... Ts>
auto push_front(std::tuple<Args...>, Ts... ts) -> std::tuple<Ts..., Args...>;

template<typename... Args>
struct tuple_helper {
    template<typename... Ts>
    using push_front = decltype(::push_front(std::tuple<Args...>{}, std::declval<Ts>()...));
};

// 递归模板:逐个重复参数包元素
template<typename... Args>
struct repeat_each;

// 空参数包的基础情况
template<>
struct repeat_each<> {
    using type = tuple_helper<>;
};

// 递归展开:对当前参数重复两次,再处理剩余参数
template<typename T, typename... Rest>
struct repeat_each<T, Rest...> {
    using type = typename repeat_each<Rest...>::type::template push_front<T, T>;
};

// 使用示例
using repeated_tuple = repeat_each<int, double>::type;
// repeated_tuple 的类型是 std::tuple<int, int, double, double>

二、运行时对参数包元素的复制操作

这种场景是指我们要对参数包里的每个元素执行复制动作(比如拷贝构造、复制到容器等)。

1. 把参数包元素复制到容器

直接用初始化列表就能把参数包的元素复制到vector这类容器里:

#include <vector>

template<typename... Args>
std::vector<typename std::common_type<Args...>::type> copy_to_vector(Args&&... args) {
    // 这里会根据参数的类型,执行值拷贝或移动构造
    return {std::forward<Args>(args)...};
}

// 使用示例
auto vec = copy_to_vector(1, 2, 3, 4);
// vec 是包含 [1,2,3,4] 的 vector<int>

2. 对每个元素执行自定义复制操作

比如我们想复制每个元素,然后打印复制后的结果,可以结合折叠表达式和自定义函数:

#include <iostream>
#include <string>

// 复制单个元素并打印
template<typename T>
void copy_and_print(const T& obj) {
    T copied_obj = obj; // 执行复制操作
    std::cout << "复制后的值:" << copied_obj << '\n';
}

// 展开参数包,对每个元素执行复制操作
template<typename... Args>
void process_copies(Args&&... args) {
    (copy_and_print(std::forward<Args>(args)), ...);
}

// 使用示例
process_copies(1, std::string("hello"), 3.14);
// 输出:
// 复制后的值:1
// 复制后的值:hello
// 复制后的值:3.14

内容的提问来源于stack exchange,提问作者Vahagn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:30:53