我想做的事情如下:

enum E;

void Foo(E e);

enum E {A, B, C};

编译器拒绝它。我在谷歌上快速浏览了一下,共识似乎是“你做不到”,但我不明白为什么。有人能解释一下吗?

澄清2:我这样做是因为我在一个类中有私有方法,它采用所说的枚举,我不希望枚举的值暴露出来-因此,例如,我不希望任何人知道E被定义为

enum E {
    FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X
}

项目X不是我想让我的用户知道的东西。

所以,我想要转发声明枚举,这样我就可以把私有方法放在头文件中,在cpp中内部声明枚举,并将构建的库文件和头分发给人们。

至于编译器——它是GCC。


当前回答

如果您真的不希望枚举出现在头文件中,并确保它只被私有方法使用,那么一种解决方案是遵循PIMPL原则。

这是一种确保在头文件中隐藏类内部信息的技术,只需声明:

class A
{
public:
    ...
private:
    void* pImpl;
};

然后在实现文件(.cpp)中声明一个类,该类将作为内部结构的表示。

class AImpl
{
public:
    AImpl(A* pThis): m_pThis(pThis) {}

    ... all private methods here ...
private:
    A* m_pThis;
};

你必须在类构造函数中动态创建实现,并在析构函数中删除它,当实现公共方法时,你必须使用:

((AImpl*)pImpl)->PrivateMethod();

使用PIMPL有优点。一个是它将类头与其实现解耦,并且在更改一个类实现时不需要重新编译其他类。另一个原因是加快了你的编译时间,因为你的头文件太简单了。

但它使用起来很痛苦,所以你应该问问自己,仅仅在头文件中将枚举声明为private是否有那么大的麻烦。

其他回答

我会这样做:

[在公共标头中]

typedef unsigned long E;

void Foo(E e);

[在内部头文件中]

enum Econtent { FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X,
  FORCE_32BIT = 0xFFFFFFFF };

通过添加FORCE_32BIT,我们可以确保Econtent编译成一个long,这样它就可以和E。

在我的项目中,我采用了命名空间限定枚举技术来处理来自遗留组件和第三方组件的枚举。这里有一个例子:

forward.h:

namespace type
{
    class legacy_type;
    typedef const legacy_type& type;
}

enum.h:

// May be defined here or pulled in via #include.
namespace legacy
{
    enum evil { x , y, z };
}


namespace type
{
    using legacy::evil;

    class legacy_type
    {
    public:
        legacy_type(evil e)
            : e_(e)
        {}

        operator evil() const
        {
            return e_;
        }

    private:
        evil e_;
    };
}

foo。:

#include "forward.h"

class foo
{
public:
    void f(type::type t);
};

foo.cc:

#include "foo.h"

#include <iostream>
#include "enum.h"

void foo::f(type::type t)
{
    switch (t)
    {
        case legacy::x:
            std::cout << "x" << std::endl;
            break;
        case legacy::y:
            std::cout << "y" << std::endl;
            break;
        case legacy::z:
            std::cout << "z" << std::endl;
            break;
        default:
            std::cout << "default" << std::endl;
    }
}

main.cc:

#include "foo.h"
#include "enum.h"

int main()
{
    foo fu;
    fu.f(legacy::x);

    return 0;
}

注意foo.h头文件不需要知道任何关于legacy::evil的信息。只有使用遗留类型legacy::evil(这里:main.cc)的文件才需要包含枚举.h。

这样我们就可以forward declare enum

enum A: int;

详情请参阅连结。

如果您真的不希望枚举出现在头文件中,并确保它只被私有方法使用,那么一种解决方案是遵循PIMPL原则。

这是一种确保在头文件中隐藏类内部信息的技术,只需声明:

class A
{
public:
    ...
private:
    void* pImpl;
};

然后在实现文件(.cpp)中声明一个类,该类将作为内部结构的表示。

class AImpl
{
public:
    AImpl(A* pThis): m_pThis(pThis) {}

    ... all private methods here ...
private:
    A* m_pThis;
};

你必须在类构造函数中动态创建实现,并在析构函数中删除它,当实现公共方法时,你必须使用:

((AImpl*)pImpl)->PrivateMethod();

使用PIMPL有优点。一个是它将类头与其实现解耦,并且在更改一个类实现时不需要重新编译其他类。另一个原因是加快了你的编译时间,因为你的头文件太简单了。

但它使用起来很痛苦,所以你应该问问自己,仅仅在头文件中将枚举声明为private是否有那么大的麻烦。

可以将枚举包装在结构体中,添加一些构造函数和类型转换,然后前向声明结构体。

#define ENUM_CLASS(NAME, TYPE, VALUES...) \
struct NAME { \
    enum e { VALUES }; \
    explicit NAME(TYPE v) : val(v) {} \
    NAME(e v) : val(v) {} \
    operator e() const { return e(val); } \
    private:\
        TYPE val; \
}

这似乎是有效的: http://ideone.com/TYtP2