如何将枚举用作模板参数?

39
我想使用一个模板类来为一些非常相似的子类提供一些共同的功能。唯一的变化是每个子类使用的枚举类型。
这是父类。
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()'

像这样,可以将枚举用作模板的参数吗?


你的构造函数定义在头文件中吗? - Lol4t0
不是的,定义在另一个源文件中。该错误在链接时出现。 - IslandCow
4个回答

63

枚举可以像整数一样作为模板参数。

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

1
模板中的枚举被视为值参数吗?我想将其用作类型。 - IslandCow
1
如果你想用 Foo<MyType> 实例化 Foo<typename T>,那么无论 MyType 是类、枚举还是其他类型都可以。你也可以使用 Foo<integer_contsant_expression> 实例化 Foo<int N>,这也是可以的。当然,前提是替换是有意义的。实现时不应该写成 if(i<T)N value; - spraff
1
这并没有展示枚举被用作模板参数。这只是展示了枚举被强制转换为整数。 - Eric
看起来这里有一个类似的问题:在C++中使用枚举作为模板类型参数 - jww
3
现在(C++11),是否也可以使用 enum class 实现这个? - Sandburg
显示剩余9条评论

9

对于值参数,语法与类型名称参数相同。基本上,你只需用你的enum名称替换typename

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

2
你是在暗示枚举被用作值而不是类型吗?主要,我试图限制哈希表中的值。 - IslandCow
2
除非你真正理解模板,否则不要编写严肃的模板代码——这有点傲慢。鼓励反馈会更有帮助。 - dlchambers
1
@dlchambers:本来不是那个意思,你说得对。我把那一节全部删除了。 - Sebastian Mach

1

你不能将模板函数的定义移动到单独的源文件中。

因为模板无法被编译,只有模板实例才能被编译,所以在那里它根本不会被编译。

你在单独的文件中的代码没有被编译,这就是为什么你实际上没有 E_EnumerationBase<TableEventEnum>::E_EnumerationBase() 的定义,这就是为什么你会得到链接错误的原因。

只需将所有模板代码移到头文件中即可。


枚举类型不会被编译成为程序的一部分。它们在类中不占用任何空间。相比之下,静态整数需要定义和分配空间。 - jww

0

仅供参考,因为你似乎在使用Qt:可以看一下Q_ENUMQMetaEnumQMetaEnum::fromType。这些函数可能有助于初始化你的字典。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接