将C ++模板类添加到列表中

时间:2022-02-27 17:03:56

I have a template class, C_Foo<T>, which is specialised in a number of ways.

我有一个模板类C_Foo ,它有很多种方法。

struct Bar_Base { ... };
struct Bar_1 : public Bar_Base { ... };
struct Bar_2 : public Bar_Base { ... };
struct Bar_3 : public Bar_Base { ... };

class C_Foo<T> { ... };

class C_Foo_1 : public C_Foo<Bar_1> { ... };
class C_Foo_2 : public C_Foo<Bar_2> { ... };
class C_Foo_3 : public C_Foo<Bar_3> { ... };

And instantiations as follows:

实例化如下:

C_Foo_1      foo1;
C_Foo_2      foo2;
C_Foo_3      foo3;

I have a set of common operations, all of which are defined on C_Foo, that I want to perform on foo1, foo2, and foo3. I've tried the following:

我有一组常见的操作,所有操作都是在C_Foo上定义的,我想在foo1,foo2和foo3上执行。我尝试过以下方法:

vector<C_Foo *>  v;
v.push_back(&foo1);
v.push_back(&foo2);
v.push_back(&foo3);

But I get compile errors, presumably because the compiler isn't sure how to go from a C_Foo_1 to a C_Foo.

但是我得到了编译错误,大概是因为编译器不确定如何从C_Foo_1转到C_Foo。

Is it possible to do something like this? I want to be able to loop through foo1 .. fooN and perform the same operations on all of them, without having to copy and paste boilerplate code like so:

有可能做这样的事吗?我希望能够循环遍历foo1 ... fooN并对所有这些操作执行相同的操作,而不必像这样复制和粘贴样板代码:

foo1.do_stuff();
foo2.do_stuff();
foo3.do_stuff();

Thanks for your help.

谢谢你的帮助。

3 个解决方案

#1


You can do that, if the function does not depend on the template parameter:

如果函数不依赖于模板参数,则可以这样做:

// note: not a template
class C_Foo_Common {
public:
    virtual void do_stuff() = 0;
};

template<typename T>
class C_Foo : public C_Foo_Common { 
    virtual void do_stuff() {
        // do stuff...
    }
};

vector<C_Foo_Common *>  v;
v.push_back(&foo1);
v.push_back(&foo2);
v.push_back(&foo3);
// now, you can iterate and call do_stuff on them. 

But if the function in C_Foo_Common needs to know the type T (for example to have another return type that depends on T), then that's not possible anymore. C_Foo<Bar_1> is a different type than C_Foo<Bar_2>. You can use discriminated unions instead. Those keep track about what is stored in them and are completely generic:

但是如果C_Foo_Common中的函数需要知道类型T(例如,要有另一个依赖于T的返回类型),那就不可能了。 C_Foo 是与C_Foo 不同的类型。您可以使用受歧视的联盟。那些跟踪存储在它们中的内容并且完全是通用的:

typedef boost::variant<
    C_Foo<Bar_1>*, C_Foo<Bar_2>*, C_Foo<Bar_3>*
> variant_type;
vector<variant_type> v;
v.push_back(&foo1);
v.push_back(&foo2);
v.push_back(&foo3);

The variant knows what it stores, and can call functions overloaded on the types of what can be stored in it. Read the documentation of boost::variant for more information on how to get at what the variants contain.

变体知道它存储的内容,并且可以调用函数重载可以存储在其中的类型。阅读boost :: variant的文档,了解有关如何获取变体包含的内容的更多信息。

#2


The problem is that C_Foo cannot be instantiated because it requires template parameters.

问题是C_Foo无法实例化,因为它需要模板参数。

You can make another base class, and have your set of common operations within that:

您可以创建另一个基类,并在其中包含一组常用操作:

class C_FooBase { ... };

template<typename T>
class C_Foo<T> : public C_FooBase { ... };

class C_Foo_1 : public C_Foo<Bar_1> { ... };
class C_Foo_2 : public C_Foo<Bar_2> { ... };
class C_Foo_3 : public C_Foo<Bar_3> { ... };

#3


This is because C_Foo<T> does not exist as a class. C_Foo<Bar1> is the real class and has nothing to do with a C_Foo<Bar2>, these are totally different classes. A template is a tool for the compiler to duplicate code, it is not a real class like generics can be in Java or C#.

这是因为C_Foo 不作为类存在。 C_Foo 是真正的类,与C_Foo 无关,这些是完全不同的类。模板是编译器复制代码的工具,它不像普通的真正的类可以是Java或C#。

If you look again at your code by thinking that C_Foo<Bar1>, C_Foo<Bar2> and C_Foo<Bar3> are totally different classes and have nothing in common, then you understand why you can't do what you want the way you want.

如果您再次查看代码,认为C_Foo ,C_Foo 和C_Foo 是完全不同的类并且没有任何共同之处,那么您就能理解为什么不能按照自己想要的方式执行所需的操作。

Like strager said, just use a real base class as the common class

像strager说的那样,只需使用真正的基类作为通用类

#1


You can do that, if the function does not depend on the template parameter:

如果函数不依赖于模板参数,则可以这样做:

// note: not a template
class C_Foo_Common {
public:
    virtual void do_stuff() = 0;
};

template<typename T>
class C_Foo : public C_Foo_Common { 
    virtual void do_stuff() {
        // do stuff...
    }
};

vector<C_Foo_Common *>  v;
v.push_back(&foo1);
v.push_back(&foo2);
v.push_back(&foo3);
// now, you can iterate and call do_stuff on them. 

But if the function in C_Foo_Common needs to know the type T (for example to have another return type that depends on T), then that's not possible anymore. C_Foo<Bar_1> is a different type than C_Foo<Bar_2>. You can use discriminated unions instead. Those keep track about what is stored in them and are completely generic:

但是如果C_Foo_Common中的函数需要知道类型T(例如,要有另一个依赖于T的返回类型),那就不可能了。 C_Foo 是与C_Foo 不同的类型。您可以使用受歧视的联盟。那些跟踪存储在它们中的内容并且完全是通用的:

typedef boost::variant<
    C_Foo<Bar_1>*, C_Foo<Bar_2>*, C_Foo<Bar_3>*
> variant_type;
vector<variant_type> v;
v.push_back(&foo1);
v.push_back(&foo2);
v.push_back(&foo3);

The variant knows what it stores, and can call functions overloaded on the types of what can be stored in it. Read the documentation of boost::variant for more information on how to get at what the variants contain.

变体知道它存储的内容,并且可以调用函数重载可以存储在其中的类型。阅读boost :: variant的文档,了解有关如何获取变体包含的内容的更多信息。

#2


The problem is that C_Foo cannot be instantiated because it requires template parameters.

问题是C_Foo无法实例化,因为它需要模板参数。

You can make another base class, and have your set of common operations within that:

您可以创建另一个基类,并在其中包含一组常用操作:

class C_FooBase { ... };

template<typename T>
class C_Foo<T> : public C_FooBase { ... };

class C_Foo_1 : public C_Foo<Bar_1> { ... };
class C_Foo_2 : public C_Foo<Bar_2> { ... };
class C_Foo_3 : public C_Foo<Bar_3> { ... };

#3


This is because C_Foo<T> does not exist as a class. C_Foo<Bar1> is the real class and has nothing to do with a C_Foo<Bar2>, these are totally different classes. A template is a tool for the compiler to duplicate code, it is not a real class like generics can be in Java or C#.

这是因为C_Foo 不作为类存在。 C_Foo 是真正的类,与C_Foo 无关,这些是完全不同的类。模板是编译器复制代码的工具,它不像普通的真正的类可以是Java或C#。

If you look again at your code by thinking that C_Foo<Bar1>, C_Foo<Bar2> and C_Foo<Bar3> are totally different classes and have nothing in common, then you understand why you can't do what you want the way you want.

如果您再次查看代码,认为C_Foo ,C_Foo 和C_Foo 是完全不同的类并且没有任何共同之处,那么您就能理解为什么不能按照自己想要的方式执行所需的操作。

Like strager said, just use a real base class as the common class

像strager说的那样,只需使用真正的基类作为通用类