如何将模板类添加为普通类中的成员

Posted

技术标签:

【中文标题】如何将模板类添加为普通类中的成员【英文标题】:How to add Template class as member within a normal class 【发布时间】:2019-09-17 17:40:10 【问题描述】:

我有一个模板类:templClass,它接受一个类型并像常规模板类一样工作。我希望该班级成为另一个普通班级regClass 的成员。 regClass 有一个成员变量var,我希望在此基础上创建templClasstype1type2: 所以如下

template <class T>
class templClass

  //constructor  
;

class regClass

public:
    regClass()
    
        // constructor for other members
    
    int var;
    templClass templClass_;
    // if (var == 0)
    // I want templClass<type1>
    // else
    // I want templClass<type2>
;

我怎样才能做到这一点? 上面的实现抛出编译器错误error: invalid use of template-name 'templClass' without an argument list

【问题讨论】:

你不能这样做。 也许告诉你要做什么会更好?看起来像 XY problem 的一个强案例。 【参考方案1】:

这是不可能的。

您必须使用类模板的显式实例化。例如

templClass<int> templClass_;

templClass<double> templClass_;

另一种选择是使regClass 也成为类模板,其中var 是模板参数而不是成员变量。

template <int> struct MemberTypeSelector;
template <> struct MemberTypeSelector<0>

   using type = templClass<int>;
;

template <> struct MemberTypeSelector<1>

   using type = templClass<double>;
;

// Add more specializations of MemberTypeSelector as needed.

template <int var>
class regClass

   public:

      using MemberType = typename MemberTypeSelector<var>::type;
      regClass()
      
         // constructor for other members
      

      MemberType member;
;

【讨论】:

或者std::variant&lt;templClass&lt;int&gt;, templClass&lt;double&gt;&gt; templClass_;然后处理std::variant成员变量的打包和解包。【参考方案2】:

正如@Eljay 在 cmets 中所说,正确的解决方案是使用std::variant

using AnyTemplClass = std::variant<templClass<int>, templClass<double>>;

class regClass

public:
    regClass()
    
        if (var == 0) 
            templClass_ = templClass<int>;
         else 
            templClass_ = templClass<double>;
         
    
    int var = 0;
    AnyTemplClass templClass_;
;

【讨论】:

【参考方案3】:

简而言之,如果我们记得模板不是类型,而是可能类型家族的名称,那么很明显,我们不能使用类型作为模板名称的类型声明数据成员。我们需要明确定义整个家族中的哪种类型是成员的类型。原因,您显然不想按类型参数化 regClass,否则您将再次拥有模板,具体取决于您使用的编译器,解决方案可以使用 union 或 std::variant 作为成员类型,但是,您需要指定所有可能的类型提前。我更喜欢按类型 T 参数化 regClass 而不是成员类型 临时类

【讨论】:

【参考方案4】:

这是不可能的。

解释这一点的最简单方法可能是实例化时刻。当你写:

regClass instance;

那么编译器无法推断出嵌入模板templClass&lt;T&gt; 类的T 类型。 templClass 本身并不是一个完整的类型。

因此你有两个选择:

    直接在regClass类定义中指定类型:
    class regClass
    
    public:
        regClass()
        
            // constructor for other members
        
        int var;
        templClass<int> templClass_;
        // [...]
    ;

这样你可以写regClass instance;,但嵌入的对象类型总是templClass&lt;int&gt;

    使外部类成为模板类:
    template <class T>
    class regClass
    
    public:
        regClass()
        
            // constructor for other members
        
        int var;
        templClass<T> templClass_;
        // [...]
    ;

这样你可以在实例化的时候决定类型,例如regClass&lt;std::string&gt; instance;.

【讨论】:

以上是关于如何将模板类添加为普通类中的成员的主要内容,如果未能解决你的问题,请参考以下文章

类模板模板类函数模板模板函数

面向对象

如何使用模板声明成员函数? (不是模板类)

C++模板类中的成员函数以及模板函数在类外定义的方式

在派生类中专门化模板成员

类和对象之模板