在C++中使用枚举作为模板类型参数

16
在C++中,使用枚举作为模板(类型)参数是否有任何限制/问题?
示例:
enum MyEnum
{
    A, B, C, D, E
};

template <typename _t>
class MyTemplate
{
public:
   _t value;

   void func(const _t& param) { /* .... */ }
};

// ....

MyTemplate<MyEnum> MyInstance;

我在Win32/x86上使用VS 2008(SP1)时,遇到了使用枚举作为模板参数的类相关的编译错误。由于我的项目变得有些复杂(你可以把它看作是设计错误:P),引发这些错误的模板类是派生的、嵌套的,甚至是基于一个带有枚举模板参数的类进行特化。
尝试构建时,编译器报告许多错误,如“C2059:语法错误:'public'”等,而在这些行中只有注释。其中许多错误我可以通过将类似于示例中的方法中的const _t& param替换为_t(即复制参数)来修复,但我既不能修复所有这些错误,也不知道为什么这样做“有用”。**我知道,上面的简单示例可以编译而没有错误。
使用int而不是枚举,我的项目可以编译而没有错误。
提前感谢任何提示或建议!
编辑:
毕竟,我认为这是编译器的一个bug。当我尝试用简化的代码重现这些错误时,在50%的“构建”中才会出现这些错误,不太确定:
例如,尝试编译,然后报告这些错误。重建 - 没有改变。删除注释,构建 - 没有改变。重建 - 然后:没有错误,编译良好。
我已经遇到了一些编译器bug(我想在20k行代码中有2或3个),但这个看起来非常奇怪。
有什么建议可以找出它是否是编译器?

3
尝试构建时,编译器报告了许多错误和无用的错误信息。这些“无用”的错误通常都有非常详细的描述,说明了出了什么问题以及在哪里出了问题。只需阅读编译器输出,而不是“错误列表”。 - SigTerm
谢谢你的提示,但我已经这样做了。我总是这样做^^但是它没有帮助我...错误:错误C2059:语法错误:'public'错误C2143:语法错误:在';'之前缺少'>'错误C2143:语法错误:在'}'之前缺少';'致命错误C1004:找到意外的文件结尾(然后还有一些其他错误,与此问题无关)所有这些错误只出现在使用枚举时,并在使用int时消失。 - dyp
这对我来说看起来完全没问题。这要么是编译器错误,要么是你的错误,如果你要猜的话,99.9%的可能性是你的问题。但是你发布的代码片段没有任何问题。请发布一个小的、完整的示例和它所产生的确切编译器错误。 - Omnifarious
我同意-查看编辑。只是想知道为什么int类型可以编译通过。 - dyp
过早的优化是我所听到的。 - Poni
显示剩余2条评论
3个回答

7

是的,有限制。例如,根据 C++03 14.3.1[temp.arg.type]/2,您不能将匿名枚举用作模板参数。

局部类型、没有链接的类型、未命名的类型或由这些类型组成的类型都不得用作模板类型参数的模板实参。

因此,以下代码在 C++03 中无效:

template <typename T>
void f(T) {}

enum {A};

int main() {
  f(A);
}

不过在C++11中这个是有效的。


5

关于原始问题的提问:

在C ++中使用枚举作为模板(类型)参数是否存在任何限制/问题?

我没有发现任何限制或问题 - 我认为没有。这种技术可能会被证明是一个坏主意,因为它并不经常使用,所以可能会有一些(更多)与此相关的编译器错误,就像Potatoswatter所说的那样。
考虑以下示例:

enum MyEnum : int
{
    A, B, C, D
};

template <typename _t> class MyTemplate
{
public:
    void print()
    {
        cout << "not using any specialisation" << endl;
    }
};
    template <> class MyTemplate <MyEnum>
    {
    public:
        void print()
        {
            cout << "MyEnum specialisation" << endl;
        }
    };
    template<> class MyTemplate <int>
    {
    public:
        void print()
        {
            cout << "int specialisation" << endl;
        }
    };

template <typename _t> void print(_t param)
{
    MyTemplate<_t> m;
    m.print();
}


int main()
{
    print(A);
    print(5);

    return 0;
}

输出结果如下:
MyEnum特例 int specialisation
对于这些简单的示例,一切都正常工作,如预期所述,枚举类型完全像任何其他类型作为模板类型参数一样正常工作(即我没有看到任何问题的原因)。
最初,我引入了这个问题中的示例,是为了展示我对此问题的看法(枚举作为模板类型参数,显示可能的用途作为成员或方法参数类型等)。为了提供一些背景,也就是为什么我问这个问题(想象一下我问“int有什么问题”),我提到了编译我的实际项目时出现的这些奇怪的问题。
很抱歉我不能提取一个完整的片段来重现错误,我最少只能得到2k行代码分成4个文件,在编译项目时会出现“语法错误:'public'”和一些其他语法错误,而它们会在某些情况下出现/消失,例如删除注释或重新构建(=删除中间文件)。不幸的是,重新构建不会帮助原始项目,我不得不将枚举类型的特化替换为int类型。
所以,感谢大家给我的提示和建议。对我而言,潜在的问题似乎是编译器bug,这使得问题有点无意义,因为答案似乎只是“没有-使用枚举作为模板类型参数没有任何限制”。对此给您带来的不便,我深感抱歉。

0

MSVC 对枚举(值)模板参数的处理有点奇怪。有时会不适当地将枚举升级为 int 并且运算符也没有被正确定义。似乎他们并没有真正用 enum 类型测试模板引擎。

证明它是编译器错误很简单:输入有效的代码并观察它是否成功编译。而你的例子显然是合规的,所以问题(或者说错误)应该在编译器那边。

编辑:经过仔细检查,你说这个例子并没有重现这个 bug。在你提供可以重现 bug 的例子之前,我们和其他任何人都无法帮助你解决问题。


只有两种方法可以证明编译器存在错误:a)根据相关标准进行验证 b)阅读文档并检查是否为已知问题/缺陷 - Chubsdad
但是,OP并没有提供枚举作为模板参数-枚举类型是该参数。 - jon hanson

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