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

如何在C++中无需指定Scheme_handle的工厂返回类型模板参数

问题:实现无需指定模板参数的Scheme_handle(无动态内存)

需求背景:

  • 使用者通过Factory构造Scheme的特殊派生类,工厂方法必须返回Table的特化类
  • 每个工厂方法对应两部分:返回的Table特化实例 + 与之兼容的Scheme特化类
  • 核心诉求:
    • 便捷性:使用者无需知晓Table与Scheme的对应关系,甚至不用知道工厂返回的Table类型
    • 支持高级用户:可强制指定要使用的Scheme特化类(因此工厂仅返回Table,且无参数)
  • 限制:不能使用动态内存,当前的Scheme_handle模板类需要用户指定模板参数,违背便捷性初衷

尝试代码:

#include<iostream>
//#include<memory> // infeasible since dynamic allocation

struct Table{ double data; };
struct Scheme{};
//
struct Table_A: Table{};
struct Table_B: Table{}; // there are too many different scheme types for use of std::conditional_t
//
struct Scheme_A: Scheme{
    Scheme_A(Table_A const& t){}
};
struct Scheme_B: Scheme{
    Scheme_B(Table_A const& t){}
    Scheme_B(Table_B const& t){}
};

struct Factory{
    /* factory implementation ... */
    static Table_A make_x(){ return Table_A{}; } // it is mandatory that Factory returns Tables
    static Table_B make_y(){ return Table_B{}; } // otherwise, Table would not have been
    static Table_A make_z(){ return Table_A{}; } // included in this minimum code example
};

// specializations still need a declaration in 2023
template<typename TableType> class Scheme_handle;

// the following two lines of terrible boilerplate are necessary 
// because c++ wont allow template<> using Scheme_handle<Table_A> = Scheme_A;
// same goes for typedef
template<> class Scheme_handle<Table_A>: public Scheme_A{ public: Scheme_handle(Table_A const& t):Scheme_A(t){} }; // Table_A -> Scheme_A
template<> class Scheme_handle<Table_B>: public Scheme_B{ public: Scheme_handle(Table_B const& t):Scheme_B(t){} }; // Table_B -> Scheme_B


// here is the consumer code that I need to be handable
struct MyClass{
    //
    // what more needs the compiler so one can drop the "<Table_A>" ?
    Scheme_handle<Table_A>   x1 = Factory::make_x(); // at least this gives me a handle to a scheme
    //
    Scheme_handle<Table_B>   y1 = Factory::make_y(); // the consumer does not possibly want to remember the scheme type of y.
    Scheme_handle<Table_B>   y2 = Factory::make_y(); // schemes arent singletons!
    //
    Scheme_B                 x2 = Factory::make_x(); // a table does not imply a scheme!
    // (but for each table there is a default compliant scheme, as defined by the mapping Scheme_handle : TableType -> SchemeType )
};

int main(){
    MyClass q;
}
解决方案

我们可以通过**C++推导指南(Deduction Guides)**让编译器自动推导Scheme_handle的模板参数,同时保留Table到Scheme的映射关系,完全满足无动态内存、便捷性与高级用户需求。

1. 重构Scheme_handle模板结构

先定义通用模板框架,再通过特化绑定Table与对应Scheme的类型关系:

// 通用模板声明
template<typename TableType>
class Scheme_handle;

// Table_A对应的特化:绑定Scheme_A
template<>
class Scheme_handle<Table_A> {
public:
    using SchemeType = Scheme_A;

    Scheme_handle(const Table_A& table) : scheme(table) {}

    // 提供Scheme实例的访问接口
    Scheme_A& get() { return scheme; }
    const Scheme_A& get() const { return scheme; }

private:
    Scheme_A scheme; // 栈上存储,无动态内存分配
};

// Table_B对应的特化:绑定Scheme_B
template<>
class Scheme_handle<Table_B> {
public:
    using SchemeType = Scheme_B;

    Scheme_handle(const Table_B& table) : scheme(table) {}

    Scheme_B& get() { return scheme; }
    const Scheme_B& get() const { return scheme; }

private:
    Scheme_B scheme;
};

2. 添加推导指南实现自动推导

通过推导指南,让编译器从传入的Table实例自动识别Scheme_handle的模板参数:

// 推导指南:根据Table类型自动推导Scheme_handle的模板参数
template<typename TableType>
Scheme_handle(const TableType&) -> Scheme_handle<TableType>;

3. 简化使用者代码

现在使用者无需手动指定模板参数,编译器会自动完成推导,同时高级用户仍可直接指定Scheme特化类:

struct MyClass{
    // 自动推导为Scheme_handle<Table_A>,无需写<Table_A>
    Scheme_handle x1 = Factory::make_x();
    // 自动推导为Scheme_handle<Table_B>
    Scheme_handle y1 = Factory::make_y();
    Scheme_handle y2 = Factory::make_y();

    // 高级用户仍可直接使用指定的Scheme特化类
    Scheme_B x2 = Factory::make_x();
};

完整可运行代码

#include<iostream>

struct Table{ double data; };
struct Scheme{};

struct Table_A: Table{};
struct Table_B: Table{};

struct Scheme_A: Scheme{
    Scheme_A(Table_A const& t){}
};
struct Scheme_B: Scheme{
    Scheme_B(Table_A const& t){}
    Scheme_B(Table_B const& t){}
};

struct Factory{
    static Table_A make_x(){ return Table_A{}; }
    static Table_B make_y(){ return Table_B{}; }
    static Table_A make_z(){ return Table_A{}; }
};

// 通用Scheme_handle模板声明
template<typename TableType>
class Scheme_handle;

// Table_A对应的特化
template<>
class Scheme_handle<Table_A> {
public:
    using SchemeType = Scheme_A;

    Scheme_handle(const Table_A& table) : scheme(table) {}

    Scheme_A& get() { return scheme; }
    const Scheme_A& get() const { return scheme; }

private:
    Scheme_A scheme;
};

// Table_B对应的特化
template<>
class Scheme_handle<Table_B> {
public:
    using SchemeType = Scheme_B;

    Scheme_handle(const Table_B& table) : scheme(table) {}

    Scheme_B& get() { return scheme; }
    const Scheme_B& get() const { return scheme; }

private:
    Scheme_B scheme;
};

// 推导指南:实现自动模板参数推导
template<typename TableType>
Scheme_handle(const TableType&) -> Scheme_handle<TableType>;

struct MyClass{
    // 自动推导模板参数,无需手动指定
    Scheme_handle x1 = Factory::make_x();
    Scheme_handle y1 = Factory::make_y();
    Scheme_handle y2 = Factory::make_y();

    // 高级用户可直接指定Scheme特化类
    Scheme_B x2 = Factory::make_x();
};

int main(){
    MyClass q;
}

方案优势

  • 零手动模板参数:普通用户无需记忆Table与Scheme的对应关系,编译器自动完成推导
  • 无动态内存:所有Scheme实例都存储在Scheme_handle内部,完全基于栈分配
  • 保留灵活性:高级用户仍可直接实例化指定的Scheme特化类,不限制自定义场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:54:52