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

C++中是否存在可变参数函数的参数容器?能否实现该容器?

问题:可变参数函数模板与自定义ArgList容器的适配

假设我们定义了如下可变参数函数模板:

template <typename... Types>
auto variadic(Types... arguments) /*...*/

是否存在一种C++容器(暂称ArgList),能够支持以下代码正常运行?

ArgList args;
args.push_back(arg1);
args.push_back(arg2);
/*...*/
variadic(args);

若不存在这类容器,是否可以实现它?


回答

C++标准库里没有直接符合需求的容器。原因很简单:标准容器要么存储同类型元素(比如std::vector),要么是编译期固定类型和大小的元组(std::tuple),没法同时满足“动态添加任意类型元素”和“直接传递给可变参数模板展开成参数列表”这两个要求。

不过我们可以自己实现一个这样的ArgList,核心是用类型擦除来存储不同类型的元素,再通过一个辅助接口把元素逐一传递给可变参数函数。

实现方案

下面是一个可行的实现思路:

  1. 用抽象基类做类型擦除,定义一个用于调用目标函数的纯虚接口。
  2. 用模板派生类存储单个元素和下一个节点,递归实现参数传递逻辑。
  3. ArgList类持有节点链的头部,提供push_back添加元素,以及apply方法触发参数展开调用。

完整代码

#include <memory>
#include <utility>

// 抽象基类:类型擦除的核心
struct ArgBase {
    virtual ~ArgBase() = default;
    template <typename... FuncArgs>
    virtual void call(auto&& func, FuncArgs&&... args) const = 0;
};

// 模板派生类:存储单个元素+下一个节点
template <typename T>
struct ArgNode : ArgBase {
    T value;
    std::unique_ptr<ArgBase> next;

    ArgNode(T val, std::unique_ptr<ArgBase> nxt)
        : value(std::move(val)), next(std::move(nxt)) {}

    template <typename... FuncArgs>
    void call(auto&& func, FuncArgs&&... args) const override {
        if (next) {
            // 递归传递当前参数,继续处理下一个节点
            next->call(std::forward<decltype(func)>(func),
                       std::forward<FuncArgs>(args)...,
                       std::forward<T>(value));
        } else {
            // 所有参数传递完毕,调用目标函数
            std::forward<decltype(func)>(func)(
                std::forward<FuncArgs>(args)...,
                std::forward<T>(value));
        }
    }
};

class ArgList {
private:
    std::unique_ptr<ArgBase> head;

public:
    ArgList() = default;

    // 禁止拷贝,允许移动语义
    ArgList(const ArgList&) = delete;
    ArgList& operator=(const ArgList&) = delete;
    ArgList(ArgList&&) = default;
    ArgList& operator=(ArgList&&) = default;

    // 添加任意类型的元素
    template <typename T>
    void push_back(T&& val) {
        head = std::make_unique<ArgNode<T>>(
            std::forward<T>(val),
            std::move(head));
    }

    // 把存储的元素展开传递给目标函数
    template <typename Func>
    void apply(Func&& func) const {
        if (head) {
            head->call(std::forward<Func>(func));
        }
    }
};

使用示例

#include <iostream>

// 目标可变参数函数
template <typename... Types>
void variadic(Types... arguments) {
    (std::cout << ... << arguments) << '\n';
}

int main() {
    ArgList args;
    args.push_back(123);
    args.push_back("hello");
    args.push_back(3.14f);

    // 方式1:显式指定模板参数
    args.apply(variadic<int, const char*, float>);
    // 方式2:用lambda自动推导参数类型
    args.apply([](auto... args) { variadic(args...); });
    return 0;
}

注意点

  • 没法直接写variadic(args),因为可变参数模板需要的是展开的参数列表,不是单个容器对象。我们通过apply方法间接完成参数的展开传递。
  • 如果不需要动态添加元素,std::tuple结合std::apply就能实现类似功能,但std::tuple的大小和类型是编译期固定的,不符合动态push_back的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:35:42