Использование перечисления в качестве параметра шаблона

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

Это родительский класс

template<typename T> class E_EnumerationBase : public SimpleElement
{
public:
    E_EnumerationBase();
    virtual bool setValue(QString choice);
    virtual T getState();

protected:
    T state;
    QHash<QString, T> dictionary;
};

template<typename T> E_EnumerationBase<T>::E_EnumerationBase() {
    state = 0;
}

template<typename T> bool E_EnumerationBase<T>::setValue(QString choice) {
    T temp;
    temp = dictionary.value(choice, 0);
    if (temp == 0) {
        return false;
    }

    value = choice;
    state = temp;
    return true;
}

template<typename T> T E_EnumerationBase<T>::getState() {
    return state;
}

Это один из детей

enum TableEventEnum {
    NO_VALUE = 0,
    ATTRACT = 1,
    OPEN = 2,
    CLOSED = 3
};

class E_TableEvent : public E_EnumerationBase<enum TableEventEnum>
{
public:
    E_TableEvent();
};

Это конструктор

E_TableEvent::E_TableEvent()
{
    state = NO_VALUE;
    dictionary.insert("attract", ATTRACT);
    dictionary.insert("open", OPEN);
    dictionary.insert("closed", CLOSED);
}

Линкером выбрасывается эта ошибка:

e_tableevent.cpp:6: error: undefined reference to `E_EnumerationBase<TableEventEnum>::E_EnumerationBase()'

Может ли перечисление использоваться в качестве параметра для шаблона, подобного этому?

Ответ 1

Перечисления могут быть параметрами шаблона точно так же, как и ints.

enum Enum { ALPHA, BETA };

template <Enum E> class Foo {
    // ...
};

template <> void Foo <ALPHA> :: foo () {
    // specialise
}

class Bar : public Foo <BETA> {
    // OK
}

Но вы просто не указали определение E_EnumerationBase::E_EnumerationBase()

Это не проблема с шаблонами или наследованием. Это так же, как если бы вы написали это:

struct Foo {
    Foo ();
}
int main () {
    Foo foo;
}

Ответ 2

Синтаксис подходит для аргументов значения, например, для аргументов typename. В основном, вы просто замените typename на имя своего enum:

enum Foo { Bar, Frob };

template <Foo F> struct Boom {};  // primary template
template <> struct Boom<Bar> {};  // specialization of whole class

...

template <> void Boom<Frob>::somefun() {}  // specialization of single member

Не записывайте серьезный код шаблона, если вы серьезно не разбираетесь в шаблонах.


Тем не менее, моя настоящая рекомендация состояла в том, чтобы сначала получить хорошее представление о шаблонах. Если вы можете потратить деньги, я рекомендую Josuttis/Vandevoorde С++ Templates: The Complete Guide

Ответ 3

Вы не можете переместить определение функции шаблона для разделения исходного файла.

Там он не будет скомпилирован вообще, потому что шаблоны не могут быть скомпилированы, только экземпляры шаблонов могут.

Ваш код в отдельном файле не скомпилирован, поэтому у вас нет определения для E_EnumerationBase<TableEventEnum>::E_EnumerationBase(). Вот почему вы получаете ошибку компоновщика.

Просто переместите весь код шаблона в свой заголовок.

Ответ 4

Просто для справки, поскольку вы, кажется, используете Qt: просто взгляните на Q_ENUM, QMetaEnum и QMetaEnum::fromType. Они могут оказаться полезными для инициализации вашего словаря.