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

如何利用捕获的构造函数参数创建新的Base类实例(C++17)

解决方案

要解决从std::vector<std::any>构造Base实例的问题,核心是保留原始构造参数的类型信息,在需要时将std::any中的值转换回正确类型后传递给Base的构造函数。以下是C++17下的实现方案:

1. 新增辅助构造逻辑

添加一个辅助命名空间,实现基于索引序列的参数转换与构造:

namespace detail {
    template <typename Base, typename... Args, std::size_t... Is>
    Base construct_base_from_args(const std::vector<std::any>& args, std::index_sequence<Is...>) {
        // 编译期校验参数数量是否匹配
        static_assert(sizeof...(Args) == args.size(), "参数数量不匹配");
        // 将每个std::any转换为原始类型,调用Base构造函数
        return Base(std::any_cast<std::decay_t<Args>>(args[Is])...);
    }
}

2. 修改Child类实现

在Child类中新增可调用对象存储构造逻辑,同时保留参数修改能力:

template<class Base>
class Child : public Base
{
public:
    template <typename... Args>
    Child(Args&&... args) :
        Base(std::forward<Args>(args)...),
        m_foo(get_penultimate(std::forward<Args>(args)...))
    {
        // 存储参数副本到m_args
        (m_args.emplace_back(std::forward<Args>(args)), ...);
        
        // 保存构造逻辑:绑定原始参数类型,生成构造器
        m_constructor = [this]() -> Base {
            return detail::construct_base_from_args<Base, Args...>(
                m_args,
                std::index_sequence_for<Args...>{}
            );
        };
    }

    // 修改倒数第二个参数(确保类型与原始参数一致)
    void updatePenultimateArg(FooType new_foo) {
        if (m_args.size() < 2) {
            throw std::invalid_argument("参数数量不足,无法修改倒数第二个参数");
        }
        m_args[m_args.size() - 2] = new_foo;
    }

    // 创建新的Base实例
    Base createBase() const {
        return m_constructor();
    }

private:
    std::vector<std::any> m_args;
    FooType m_foo;
    // 存储构造Base的逻辑,通过std::function实现类型擦除
    std::function<Base()> m_constructor;
};

关键说明

  • 类型信息保留:Child的构造函数通过成员模板捕获原始参数类型Args...,并将对应的构造逻辑存储到m_constructor中,解决了std::any丢失类型信息的问题。
  • 参数转换与构造:借助std::index_sequence和折叠表达式,遍历m_args中的每个元素,用std::any_cast转换为原始类型后传递给Base的构造函数。
  • 安全性:修改倒数第二个参数时,确保赋值的FooType与原始参数类型一致,避免std::bad_any_cast异常;编译期的static_assert会校验参数数量是否匹配。

使用示例

// 构造Child实例
Child<MyBase> child{1, FooType{}, "hello"};

// 修改倒数第二个参数
child.updatePenultimateArg(FooType{new_value});

// 创建新的Base实例
MyBase new_base = child.createBase();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:06:06