当前位置: 首页 > 知识库问答 >
问题:

从可变类模板为每个类型生成一个方法

汪晟睿
2023-03-14

我想有一个可变的类模板来生成每种类型的一个方法,例如像下面这样的类模板:

template <class T, class ... Ts>
class MyClass {
public:
    virtual void hello(const T& t) = 0;
};

将使方法你好(const双

请注意,我希望该类是纯抽象的,因此派生类实际上需要进行实现,例如:

class Derived : MyClass<double, int> {
public:
    inline void hello(const double& t) override { }
    inline void hello(const int& t) override { }
};

这个问题和这个问题有点相似,但是我不明白如何使它适应我的情况。

编辑

递归继承对我来说似乎是正确的解决方案。这种更复杂的情况怎么样,超类有不止一个方法,模板参数是强制性的?以下是我尝试过的(但我得到了错误):

template <class MandatoryT, class OptionalT, class... MoreTs>
class MyClass : public MyClass<MandatoryT, MoreTs...> {
public:
    virtual ~MyClass() {}

    virtual char* goodmorning(const MandatoryT& t) = 0;

    virtual bool bye(const MandatoryT& t,
                     const std::map<std::string,bool>& t2) = 0;

  using MyClass<MandatoryT, MoreTs...>::hello;
  virtual void hello(const OptionalT& msg) = 0;
};


template <class MandatoryT, class OptionalT>
class MyClass<MandatoryT, OptionalT> {
  virtual void processSecondaryMessage(const OptionalT& msg) = 0;
};

template <class MandatoryT>
class MyClass<MandatoryT> {
  virtual void processSecondaryMessage() = 0;
}
}

基本上我想要的是派生类应该有一个或多个类型。第一种方法用于其他方法,而从第二种方法开始,它应用于hello()。如果只提供一种类型,则调用空的hello()。但是当至少提供了第二种类型时,hello()应该使用它。

上面的代码抱怨至少应该有两个模板参数,因为有“两个”基例而不是一个。


共有1个答案

隆璞
2023-03-14

也许其他人可以做得更好,但我认为只有两种方法

>

  • 递归继承

    您可以如下递归地定义MyClass

    // recursive case
    template <typename T, typename ... Ts>
    struct MyClass : public MyClass<Ts...>
     {
       using MyClass<Ts...>::hello;
    
       virtual void hello (const T&) = 0;
     };
    
    // ground case
    template <typename T>
    struct MyClass<T>
     { virtual void hello (const T&) = 0; };
    

    变异遗传

    您可以定义另一个类/结构,比如说MyHello,它声明一个hello()方法,并可变地从MyClass继承它。

    template <typename T>
    struct MyHello
     { virtual void hello (const T&) = 0; };
    
    template <typename ... Ts>
    struct MyClass : public MyHello<Ts>...
     { };
    

    递归示例与类型冲突兼容(也就是说:当一个类型在模板参数列表MyClass中出现更多时间时也有效;通过示例MyClass

    不幸的是,可变遗传案例并非如此。

    下面是一个完整的编译示例

    #if 1
    // recursive case
    template <typename T, typename ... Ts>
    struct MyClass : public MyClass<Ts...>
     {
       using MyClass<Ts...>::hello;
    
       virtual void hello (const T&) = 0;
     };
    
    // ground case
    template <typename T>
    struct MyClass<T>
     { virtual void hello (const T&) = 0; };
    #else
    
    template <typename T>
    struct MyHello
     { virtual void hello (const T&) = 0; };
    
    template <typename ... Ts>
    struct MyClass : public MyHello<Ts>...
     { };
    
    #endif
    
    struct Derived : public MyClass<double, int>
     {
       inline void hello (const double&) override { }
       inline void hello (const int&) override { }
     };
    
    int main()
     {
       Derived d;
    
       d.hello(1.0);
       d.hello(2);
     }
    

    --编辑--

    OP问道

    如果MyClass有多个方法,并且我总是需要一个模板参数(请参见编辑的问题),那么更复杂的情况如何?

    从你的问题来看,我不明白你到底想要什么。

    但是,假设您想要一个纯虚拟方法,比如说,goodmorning()接收MandT(强制类型),对于MandT之后的每个类型,都需要一个纯虚拟方法hello(),或者当MandT之后的列表为空时,不带参数的hello()

    一个可能的解决方案如下

    // declaration and groundcase with only mandatory type (other cases
    // intecepted by specializations)
    template <typename MandT, typename ...>
    struct MyClass
     {
       virtual void hello () = 0;
    
       virtual ~MyClass () {}
    
       virtual char * goodmorning (MandT const &) = 0;
     };
    
    // groundcase with a single optional type
    template <typename MandT, typename OptT>
    struct MyClass<MandT, OptT>
     {
       virtual void hello (OptT const &) = 0;
    
       virtual ~MyClass () {}
    
       virtual char * goodmorning (MandT const &) = 0;
     };
    
    // recursive case
    template <typename MandT, typename OptT, typename ... MoreOptTs>
    struct MyClass<MandT, OptT, MoreOptTs...>
       : public MyClass<MandT, MoreOptTs...>
     {
       using MyClass<MandT, MoreOptTs...>::hello;
    
       virtual void hello (OptT const &) = 0;
    
       virtual ~MyClass () {}
     };
    

    这里的递归比以前稍微复杂一些。

    如果您仅使用强制类型实例化MyClass(例如:MyClass)

    如果您实例化一个MyClass与一个可选类型(如MyClass

    如果你实例化一个MyClass有两个或更多可选类型(比如MyClass

    注意,我将goodmorning()放在两种基本情况下,因为您不需要递归地定义它。

    下面是一个完整的编译示例

    // declaration and groundcase with only mandatory type (other cases
    // intecepted by specializations)
    template <typename MandT, typename ...>
    struct MyClass
     {
       virtual void hello () = 0;
    
       virtual ~MyClass () {}
    
       virtual char * goodmorning (MandT const &) = 0;
     };
    
    // groundcase with a single optional type
    template <typename MandT, typename OptT>
    struct MyClass<MandT, OptT>
     {
       virtual void hello (OptT const &) = 0;
    
       virtual ~MyClass () {}
    
       virtual char * goodmorning (MandT const &) = 0;
     };
    
    // recursive case
    template <typename MandT, typename OptT, typename ... MoreOptTs>
    struct MyClass<MandT, OptT, MoreOptTs...>
       : public MyClass<MandT, MoreOptTs...>
     {
       using MyClass<MandT, MoreOptTs...>::hello;
    
       virtual void hello (OptT const &) = 0;
    
       virtual ~MyClass () {}
     };
    
    
    struct Derived0 : public MyClass<char>
     {
       void hello () override { }
    
       char * goodmorning (char const &) override
        { return nullptr; }
     };
    struct Derived1 : public MyClass<char, double>
     {
       void hello (double const &) override { }
    
       char * goodmorning (char const &) override
        { return nullptr; }
     };
    
    struct Derived2 : public MyClass<char, double, int>
     {
       void hello (double const &) override { }
       void hello (int const &) override { }
    
       char * goodmorning (char const &) override
        { return nullptr; }
     };
    
    
    
    int main()
     {
       Derived0  d0;
       Derived1  d1;
       Derived2  d2;
    
       d0.hello();
       d0.goodmorning('a');
    
       d1.hello(1.2);
       d1.goodmorning('b');
    
       d2.hello(3.4);
       d2.hello(5);
       d2.goodmorning('c');
     }
    

  •  类似资料:
    • 我有一个模板类,其中每个模板参数代表内部计算可以处理的一种类型的值。需要模板(而不是函数重载),因为值被作为::any传递,并且它们的类型在运行时之前不清楚。 为了正确地转换为正确的类型,我希望每个变量参数类型都有一个成员列表,类似于这样: 或者,我想将模板参数类型存储在一个列表中,以便对其进行RTTI处理(?)。但如何将它们保存在std::initializer\u列表成员中,我也不清楚。 谢谢

    • 我试图从一组可变的模板类(其中每个类都有一个非类型参数)中恢复非typename模板参数,以便在另一种类型中将它们用作整数序列。 下面的代码显示了我所拥有的。整数序列/成员序列是从元组中抄袭出来的。 和的类型是

    • 变量通用属性 变量通用属性有title,value,type,tip,rule,message,除了通用属性个别变量还有其它属性,请看每个具体控件; "vars": { "varName1": { "title": "测试 text", /*后台设置时 input 的 label*/ "value": "1", /*变量默认值*/ "type

    • 变量通用属性 变量通用属性有title,value,type,tip,rule,message,除了通用属性个别变量还有其它属性,请看每个具体控件; "vars": { "varName1": { "title": "测试 text", /*后台设置时 input 的 label*/ "value": "1", /*变量默认值*/ "type

    • 我是新使用模板。作为标题,我有一个非模板类(Obj和ObjBase)和一个模板类pitem。我想让pItem::RefValue()访问obj中的私有成员。 我想下面的行得通: 它不: 错误C2248:“obj::GetValue”:无法访问类“obj”中声明的私有成员 注意:请参阅对正在编译的函数模板实例化“int PItem::GetValue(void)”的引用 编译器投诉:

    • 我有以下xml类型: FaxNumber类型如下所示: 生成的xml应该如下所示: 运行JAXB XJC从XSD生成java类时,它会生成以下类: 但是,我想绑定FaxNumber到这样的复合类: 有没有办法在JAXB绑定xml中定义这样的绑定? 注意:不幸的是,我无法控制并且无法更改XSD