39

I would like to use a template class to provide some common functionality to some child classes that are very similar. The only variation is the enumeration that each uses.

This is the parent class

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

This is one of the children

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

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

This is the constructor

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

The linker is throwing this error:

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

Can an enumeration be used as the parameter to a template like this?

IslandCow
  • 3,412
  • 3
  • 19
  • 24

4 Answers4

62

Enumerations can be template parameters in exactly the same way that ints can.

enum Enum { ALPHA, BETA };

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

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

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

But you simply haven't provided a definition for E_EnumerationBase::E_EnumerationBase()

This isn't a problem with templates or inheritence. It's the same as if you written this:

struct Foo {
    Foo ();
}
int main () {
    Foo foo;
}
spraff
  • 32,570
  • 22
  • 121
  • 229
  • Can you please post it to [ideone.com](http://www.ideone.com) or similar in such a form that that is the only error? It would be helpful to see line numbers etc. For now I don't believe that `public E_EnumerationBase` compiles at all. – spraff Feb 02 '12 at 16:58
  • 1
    Are enumerations in templates treated as value arguments? I would like to use it as a type. – IslandCow Feb 02 '12 at 17:06
  • 1
    If you want to instantinate `Foo` with `Foo` that's ok whether `MyType` is a class or enum or any other type. You can also instantinate `Foo` with `Foo` and that's also ok. Provided, of course, that the substitution makes sense. The implementations should not write `if(i – spraff Feb 02 '12 at 17:27
  • How do you enforce `template ` only takes values `ALPHA` and `BETA`? What stops someone from instantiating with `E=99`? Does it at least generate a warning? – jww Dec 04 '16 at 08:09
  • With `template` you can instantiate with any `int`, with `template` you can instantiate with any `Enum`. Normal int/enum casting constraints apply. – spraff Dec 05 '16 at 14:33
  • 1
    This doesn't show enumerations being used as template parameters. This just shows enums being cast to ints. – Eric Dec 29 '16 at 18:50
  • [No](http://pastebin.com/EYF2eDAc), these are enum-typed parameters. Enum *values* may be type-converted to ints, but enum *types* don't. – spraff Dec 30 '16 at 17:55
  • @spraff: your link there is what I was expecting your answer to contain – Eric Dec 30 '16 at 18:44
  • Ah, I see what you mean. Edited. – spraff Dec 31 '16 at 14:10
  • *Enumerations can be template parameters in exactly the same way that ints can..."* - Is that C++03 or C++11? Do you know how well earlier compilers supported it? "Earlier" means compilers like GCC 4.4, Clang 3.2, MSC 14.0. (We are in a special hell due to backwards compatibility). – jww Aug 05 '17 at 10:28
  • It looks like here is a similar question: [Using enum as template type argument in C++](https://stackoverflow.com/q/3485472/608639) – jww Aug 05 '17 at 10:39
  • I must say that the fact that you named your enum as 'Enum' made me spend quite some time trying to understand this. I suggest changing it to something like 'Greek' to make the example clearer – Frederico Pantuzza Nov 23 '17 at 09:20
  • 3
    Is it now (C++11) also possible with `enum class` ? – Sandburg Apr 19 '19 at 15:04
9

The syntax goes for value arguments like it is for typename arguments. Basically, you just replace typename with the name of your 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
Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • 2
    Are you suggesting the enum is being used for its value and not as a type? Primarily, I'm trying to restrict the values in the hash table. – IslandCow Feb 02 '12 at 17:18
  • 2
    "Don't write serious template code unless you seriously understand templates" - that's a bit arrogant. Encouraging feedback would be more helpful. – dlchambers Sep 26 '18 at 12:33
  • 1
    @dlchambers: It wasn't intended that way and you are right. I removed that section altogether. – Sebastian Mach Sep 26 '18 at 12:38
1

You cannot move definition of template function to separate source file.

There it wouldn't be compiled at all, because templates can't be compiled, only template instances can.

Your code in separate file isn't get compiled, that's why you actually have no definition for E_EnumerationBase<TableEventEnum>::E_EnumerationBase(). That's why you get linker error.

Just move all template code to your header.

Lol4t0
  • 12,444
  • 4
  • 29
  • 65
  • *There [the enum] wouldn't be compiled at all"* - Enums don't get compiled *per se*. They take up no space in the class. This is in contrast to, say, a static int which requires a definition and causes an allocation. – jww Aug 05 '17 at 10:31
0

Just for reference, as you seem to use Qt: Just have a look at Q_ENUM, QMetaEnum and QMetaEnum::fromType. These may come handy to initialize your dictionary.

Kamajii
  • 1,826
  • 9
  • 21