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

嵌套类的访问变体:如何避免C++代码冗余?

问题:精简多态类配置实例化的冗余代码

我有大量继承自Base的多态类,每个类都包含名为Configuration的嵌套结构体,用于存储该类的全部超参数。针对这个类层级,我用std::variant存储所有可能的配置变体,并提供instantiate函数从配置生成实例。原始实现如下:

#include <variant>
#include <memory>

class Base
{};

class A : public Base
{
public:
    struct Configuration { /*超参数*/ };
    A(Configuration const&) {}
};

class B : public Base
{
public:
    struct Configuration { /*超参数*/ };
    B(Configuration const&) {}
};

struct BaseConfiguration
{
    using type = std::variant<A::Configuration, B::Configuration>;
    static std::unique_ptr<Base> instantiate(type const& config);
};

struct BaseVisitor
{
    // 这里存在大量重复逻辑
    std::unique_ptr<Base> operator()(A::Configuration const& config)
    { return std::make_unique<A>(config); }
    std::unique_ptr<Base> operator()(B::Configuration const& config)
    { return std::make_unique<B>(config); }
};

std::unique_ptr<Base> BaseConfiguration::instantiate(type const& config)
{
    return std::visit(BaseVisitor(), config);
}

int main()
{
    BaseConfiguration::type config = A::Configuration();
    std::unique_ptr<Base> x = BaseConfiguration::instantiate(config);
    return 0;
}

BaseVisitor中的每个operator()逻辑完全一致,但类数量多时代码冗余严重。我尝试用模板精简,但C++17环境下编译失败:

struct BaseVisitor
{
    template <typename X>
    std::unique_ptr<Base> operator()(typename X::Configuration const& config)
    { return std::make_unique<X>(config); }
};

编译器错误:

<source>: In static member function 'static std::unique_ptr<Base> BaseConfiguration::instantiate(const type&)':
<source>:36:22: error: no matching function for call to 'visit(BaseVisitor, const BaseConfiguration::type&)'
   36 |     return std::visit(BaseVisitor(), config);
      |            ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~

原因分析

原模板方案失败的核心原因是:typename X::Configuration属于非推导上下文,编译器无法从传入的A::Configuration或B::Configuration参数反向推导出模板参数X,导致std::visit无法找到匹配的重载。


解决方案

方案一:给Configuration添加类型别名

在每个类的Configuration中添加指向所属类的类型别名,让Visitor可以直接通过配置类型获取目标类:

#include <variant>
#include <memory>

class Base
{};

class A : public Base
{
public:
    struct Configuration { 
        using TargetType = A; // 添加类型别名
        /*超参数*/ 
    };
    A(Configuration const&) {}
};

class B : public Base
{
public:
    struct Configuration { 
        using TargetType = B; // 添加类型别名
        /*超参数*/ 
    };
    B(Configuration const&) {}
};

struct BaseConfiguration
{
    using type = std::variant<A::Configuration, B::Configuration>;
    static std::unique_ptr<Base> instantiate(type const& config);
};

struct BaseVisitor
{
    // 单一模板处理所有配置类型
    template <typename Config>
    std::unique_ptr<Base> operator()(Config const& config)
    {
        return std::make_unique<typename Config::TargetType>(config);
    }
};

std::unique_ptr<Base> BaseConfiguration::instantiate(type const& config)
{
    return std::visit(BaseVisitor(), config);
}

int main()
{
    BaseConfiguration::type config = A::Configuration();
    std::unique_ptr<Base> x = BaseConfiguration::instantiate(config);
    return 0;
}

方案二:使用类型 trait 映射配置与类

如果不想修改Configuration结构体,可以用类型 trait 模板实现配置到目标类的映射:

#include <variant>
#include <memory>

class Base
{};

class A : public Base
{
public:
    struct Configuration { /*超参数*/ };
    A(Configuration const&) {}
};

class B : public Base
{
public:
    struct Configuration { /*超参数*/ };
    B(Configuration const&) {}
};

// 定义类型 trait
template <typename Config>
struct ConfigToTarget;

// 特化每个配置对应的目标类
template <>
struct ConfigToTarget<A::Configuration> { using type = A; };
template <>
struct ConfigToTarget<B::Configuration> { using type = B; };

// 简化 trait 调用的别名
template <typename Config>
using ConfigToTarget_t = typename ConfigToTarget<Config>::type;

struct BaseConfiguration
{
    using type = std::variant<A::Configuration, B::Configuration>;
    static std::unique_ptr<Base> instantiate(type const& config);
};

struct BaseVisitor
{
    template <typename Config>
    std::unique_ptr<Base> operator()(Config const& config)
    {
        return std::make_unique<ConfigToTarget_t<Config>>(config);
    }
};

std::unique_ptr<Base> BaseConfiguration::instantiate(type const& config)
{
    return std::visit(BaseVisitor(), config);
}

int main()
{
    BaseConfiguration::type config = A::Configuration();
    std::unique_ptr<Base> x = BaseConfiguration::instantiate(config);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:53:20