Добавление шаблонных классов C ++ в список - PullRequest
1 голос
/ 02 февраля 2009

У меня есть шаблон класса, 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> { ... };

И следующие экземпляры:

C_Foo_1      foo1;
C_Foo_2      foo2;
C_Foo_3      foo3;

У меня есть набор общих операций, все из которых определены в C_Foo, которые я хочу выполнить на foo1, foo2 и foo3. Я пробовал следующее:

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

Но я получаю ошибки компиляции, предположительно потому, что компилятор не уверен, как перейти от C_Foo_1 к C_Foo.

Возможно ли сделать что-то подобное? Я хочу иметь возможность циклически проходить через foo1 .. fooN и выполнять одни и те же операции со всеми из них, без необходимости копировать и вставлять шаблонный код, например, так:

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

Спасибо за вашу помощь.

Ответы [ 3 ]

6 голосов
/ 02 февраля 2009

Это можно сделать, если функция не зависит от параметра шаблона:

// 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. 

Но если функция в C_Foo_Common должна знать тип T (например, иметь другой тип возвращаемого значения, зависящий от T), то это больше невозможно. C_Foo<Bar_1> отличается от C_Foo<Bar_2>. Вместо этого вы можете использовать дискриминационные союзы. Они отслеживают, что в них хранится, и являются полностью общими:

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);

Вариант знает, что он хранит, и может вызывать функции, перегруженные типами того, что в нем может храниться. Прочитайте документацию boost::variant для получения дополнительной информации о том, как получить то, что содержат варианты.

4 голосов
/ 02 февраля 2009

Проблема в том, что экземпляр C_Foo не может быть создан, поскольку он требует параметров шаблона.

Вы можете создать другой базовый класс и иметь в нем набор общих операций:

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> { ... };
2 голосов
/ 02 февраля 2009

Это потому, что C_Foo не существует как класс. C_Foo является реальным классом и не имеет ничего общего с C_Foo , это совершенно разные классы. Шаблон - это инструмент для компилятора для дублирования кода, это не настоящий класс, как дженерики могут быть в Java или C #.

Если вы снова посмотрите на свой код, думая, что C_Foo , C_Foo и C_Foo абсолютно разные классы и не имеют ничего общего, то вы поймете, почему вы не можете делать то, что хотите, так, как ты хочешь.

Как сказал Стрейджер, просто используйте реальный базовый класс в качестве общего класса

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...