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

如何在C++中虚拟拼接不同类型的std::vector以统一处理

问题描述

需要在函数调用期间虚拟拼接两个存储不同类型对象的C++ std::vector,让函数能将它们作为整体处理,同时满足以下限制:

  • 不使用虚函数、动态内存分配
  • 不将不同类型对象(或其指针)放入同一容器(多数场景下需区别处理,不愿付出额外开销或设计复杂接口)
  • 避免逐个处理向量导致的代码重复,新增类型时无需手动更新大量重复代码
  • 后续需求升级为:需要动态拼接向量的别名,而非仅在调用时临时拼接

现有代码草稿如下:

#include <vector>
#include <iostream>

struct A {
  void foo() { std::cout << "Hey, I'm A!\n"; }
};

struct B {
  void foo() { std::cout << "Hey, I'm B!\n"; }
};

void bar(???) {
   ???.foo();
}

int main()  {
    std::vector<A> va(2);
    std::vector<B> vb(3);

    bar(???);
    return 0;
}
解决方案

1. 调用时虚拟拼接:可变参数模板遍历多容器

利用C++11及以上的可变参数模板,实现通用遍历函数,无需实际拼接容器,依次遍历每个传入的容器执行操作,完全在编译期展开,无额外开销。

实现代码

#include <vector>
#include <iostream>

struct A {
  void foo() { std::cout << "Hey, I'm A!\n"; }
};

struct B {
  void foo() { std::cout << "Hey, I'm B!\n"; }
};

// 递归终止函数:无更多容器时停止
void bar() {}

// 可变参数模板:遍历当前容器,再递归处理剩余容器
template <typename Container, typename... Rest>
void bar(const Container& container, const Rest&... rest) {
    for (const auto& elem : container) {
        elem.foo();
    }
    bar(rest...);
}

int main()  {
    std::vector<A> va(2);
    std::vector<B> vb(3);

    bar(va, vb); // 直接传入多容器,虚拟拼接遍历
    return 0;
}

说明

  • 新增类型时,只要元素有foo()成员函数,直接传入对应容器即可,无需修改bar函数
  • 彻底避免重复编写多个容器的遍历逻辑

2. 动态拼接向量别名:轻量级视图类封装

如果需要可复用的"虚拟拼接容器",可以实现一个视图类,持有多个容器的引用,对外提供统一遍历接口,模拟单个容器的行为,无动态内存分配。

实现代码

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

struct A {
  void foo() { std::cout << "Hey, I'm A!\n"; }
};

struct B {
  void foo() { std::cout << "Hey, I'm B!\n"; }
};

// 虚拟拼接视图类,支持任意数量、类型的容器
template <typename... Containers>
class JoinedView {
private:
    std::tuple<const Containers&...> containers_;

    // 递归遍历所有容器执行操作
    template <size_t Index = 0>
    void for_each_impl(auto&& func) const {
        if constexpr (Index < sizeof...(Containers)) {
            const auto& container = std::get<Index>(containers_);
            for (const auto& elem : container) {
                func(elem);
            }
            for_each_impl<Index + 1>(std::forward<decltype(func)>(func));
        }
    }

public:
    explicit JoinedView(const Containers&... containers) : containers_(containers...) {}

    // 统一遍历接口
    void for_each(auto&& func) const {
        for_each_impl(std::forward<decltype(func)>(func));
    }
};

// 辅助函数简化视图创建
template <typename... Containers>
auto join(const Containers&... containers) {
    return JoinedView<Containers...>(containers...);
}

// 使用视图的bar函数
void bar(const auto& joined_view) {
    joined_view.for_each([](const auto& elem) {
        elem.foo();
    });
}

int main()  {
    std::vector<A> va(2);
    std::vector<B> vb(3);

    auto joined = join(va, vb); // 创建动态拼接的视图别名
    bar(joined);

    // 视图可复用,还能随时添加更多容器
    std::vector<A> va2(1);
    auto joined2 = join(va, vb, va2);
    bar(joined2);
    return 0;
}

说明

  • JoinedView仅持有容器引用,开销极小,符合无动态分配要求
  • 支持任意数量、类型的容器,只要元素有统一操作接口即可
  • 视图可作为"虚拟拼接容器"复用,随时调整包含的容器

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:05:26