gpt4 book ai didi

c++11 - 从可变参数类模板为每种类型生成一个方法

转载 作者:行者123 更新时间:2023-12-01 12:05:54 26 4
gpt4 key购买 nike

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

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

将使方法可用 hello(const double&)hello(const int&)当实例化为 MyClass<double, int> myclass;

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

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

这个问题有点类似to this one , 但我不明白如何使它适应我的情况。

编辑

递归继承对我来说似乎是正确的解决方案。这个更复杂的情况怎么样,其中父类(super class)有多个方法并且模板参数是强制性的?这是我尝试过的方法(但出现错误):

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. 递归继承

    你可以定义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; };

  1. 可变继承

    您可以定义另一个类/结构,比如 MyHello ,声明一个单例hello()方法,可变参数继承自 MyClass .

    template <typename T>
    struct MyHello
    { virtual void hello (const T&) = 0; };

    template <typename ... Ts>
    struct MyClass : public MyHello<Ts>...
    { };

递归示例与类型冲突兼容(即:当类型在模板参数列表中出现更多时间时也有效 MyClass ;例如 MyClass<int, double, int> )。

不幸的是,可变参数继承情况并非如此。

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

#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 要求

how about a more complicated case where MyClass has more than one method and I always need to have one template argument (see edited question)?

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

但是假设你想要一个纯虚方法,比如说 goodmorning()收到MandT (强制类型),纯虚方法hello()对于以下 MandT 的每种类型或 hello() MandT 之后的列表不带参数是空的。

可能的解决方案如下

// 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<char>)选择了主要版本(“groundcase with only mandatory type”),因为两个特化不匹配(没有第一个可选类型)。

如果您实例化一个 Myclass对于一种可选类型(例如 MyClass<char, double> ),选择特化“具有单一可选类型的 groundcase”,因为它是最专业的版本。

如果您实例化一个 MyClass具有两个或多个可选类型(比如 MyClass<char, double, int> 开始递归(最后的特化)直到保持单个可选类型(因此选择“具有单个可选类型的基本情况”)。

注意我已经放置了 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');
}

关于c++11 - 从可变参数类模板为每种类型生成一个方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56995453/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com