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

如何用可变参数模板实现多任意类型std::vector的并排打印函数?

实现多vector并排打印的解决方案

你的问题核心是如何在同一作用域中访问所有传入的vector参数,以便按索引并行遍历——递归分离参数的方式确实做不到这一点,因为它每次只处理一个参数,没法同时拿到所有vector的同一索引元素。下面提供两种实用的实现方案,分别适配C17及以上,和C11/14版本。

方案一:C++17 折叠表达式(简洁首选)

C++17引入的折叠表达式可以直接展开参数包,结合tuple来统一管理所有vector,这样就能在循环的每个索引步中访问所有参数的对应元素。

#include <iostream>
#include <vector>
#include <tuple>

template <typename... Ts>
void printV(const std::vector<Ts>&... vecs) {
    // 处理空调用的边界情况
    if constexpr (sizeof...(vecs) == 0) {
        return;
    }

    // 以第一个vector的长度为基准(你假设所有vector长度一致)
    const auto total_rows = std::get<0>(std::make_tuple(vecs...)).size();

    for (std::size_t i = 0; i < total_rows; ++i) {
        std::cout << i << ": ";
        
        // 先打印第一个元素,避免开头出现多余逗号
        std::cout << std::get<0>(std::make_tuple(vecs...)).at(i);
        
        // 用折叠表达式遍历剩余所有vector,打印逗号+元素
        ((std::cout << ", " << vecs.at(i)), ...);
        
        std::cout << '\n';
    }
}

代码说明:

  1. std::make_tuple(vecs...)把所有传入的vector打包成一个tuple,方便统一访问;
  2. if constexpr是C++17的编译期条件判断,避免空调用时出错;
  3. 折叠表达式((std::cout << ", " << vecs.at(i)), ...)会自动展开为:
    std::cout << ", " << vec1.at(i);
    std::cout << ", " << vec2.at(i);
    ...
    std::cout << ", " << vecN.at(i);
    

方案二:C++11/14 适配版(无折叠表达式)

如果你的环境不支持C17,可以用tuple+索引序列的方式模拟参数包展开,这是C11标准下处理可变参数的经典技巧。

#include <iostream>
#include <vector>
#include <tuple>
#include <utility> // 用于std::index_sequence

namespace detail {
    // 辅助函数:打印单行的所有vector元素
    template <typename Tuple, std::size_t... Is>
    void print_single_row(std::size_t row_idx, const Tuple& vec_tuple, std::index_sequence<Is...>) {
        std::cout << row_idx << ": ";
        bool is_first_element = true;
        
        // 用"吞掉数组"技巧展开参数包(C++11无折叠表达式的替代方案)
        using swallow = int[];
        (void)swallow{0, (
            [&]() {
                if (!is_first_element) {
                    std::cout << ", ";
                }
                std::cout << std::get<Is>(vec_tuple).at(row_idx);
                is_first_element = false;
            }(), 0)...};
        
        std::cout << '\n';
    }

    // 辅助函数:遍历所有行,调用单行打印
    template <typename Tuple>
    void print_all_rows(const Tuple& vec_tuple) {
        const auto total_rows = std::get<0>(vec_tuple).size();
        // 生成索引序列:0,1,...,N-1(N是vector的数量)
        using indices = std::make_index_sequence<std::tuple_size<Tuple>::value>;
        
        for (std::size_t i = 0; i < total_rows; ++i) {
            print_single_row(i, vec_tuple, indices{});
        }
    }
}

// 对外暴露的接口函数
template <typename... Ts>
void printV(const std::vector<Ts>&... vecs) {
    if (sizeof...(vecs) == 0) {
        return;
    }
    // 将所有vector打包成tuple,传递给内部函数处理
    auto vec_tuple = std::make_tuple(vecs...);
    detail::print_all_rows(vec_tuple);
}

代码说明:

  1. std::index_sequence会生成一个编译期的整数序列,对应tuple中每个vector的索引;
  2. "吞掉数组"技巧(void)swallow{0, (... ,0)}是C++11中用来强制展开参数包的常用方法,确保每个vector的元素都会被处理;

测试示例

不管用哪个方案,你都可以像这样调用:

int main() {
    std::vector<int> v1 = {1, 2, 3};
    std::vector<double> v2 = {1.5, 2.5, 3.5};
    std::vector<std::string> v3 = {"foo", "bar", "baz"};
    
    printV(v1, v2, v3);
}

输出结果:

0: 1, 1.5, foo
1: 2, 2.5, bar
2: 3, 3.5, baz

扩展提示

如果需要处理vector长度不一致的情况,可以修改代码取所有vector中最小的长度作为循环上限,或者对超出长度的vector打印占位符(比如"N/A"),只需要在获取total_rows时做一下计算:

// C++17版本示例:取最小长度
const auto total_rows = std::min({vecs.size()...});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:42:11