简体   繁体   English

c ++ typedef另一个类的枚举?

[英]c++ typedef another class's enum?

So here's my problem: 所以这是我的问题:

struct A
{
    enum A_enum
    {
        E0,
        E1,
        E2
    };
};

struct B
{
    typedef A::A_enum B_enum;
    bool test(B_enum val)
    {
        return (val == E1); // error: "E1" undeclared identifier
    }
};

I specifically do not want to say A::E1 . 我特意不想说A::E1 If I try B_enum::E1 I receive a warning that it is nonstandard. 如果我尝试B_enum::E1我会收到一个非标准的警告。 Is there a good way to do something like this? 有没有办法做这样的事情?

我认为A应该是命名空间而不是结构。

Putting enum in global scope is too exposed, putting them in a class can introduced undesired dependency. 将枚举放在全局范围内太暴露了,将它们放在一个类中会引入不受欢迎的依赖。 For enum not tightly link to a class, this is what I use: 对于enum没有紧密链接到类,这是我使用的:

#define CLEANENUMS_BEGIN(name) namespace name { typedef enum {
#define CLEANENUMS_END(name) } internal_ ## name ## _e;} typedef name::internal_ ## name ## _e name ## _e;

Then you can use, at global scope: 然后你可以在全球范围内使用:

CLEANENUMS_BEGIN(myEnum)
    horizontal,
    vertical,
CLEANENUMS_END(myEnum)

That is more or less emulating C# way of handling enums scope. 这或多或少模仿处理枚举范围的C#方式。 The preprocessor will produce this code: 预处理器将生成以下代码:

namespace myEnum
{
    enum internal_myEnum_e
    {
        horizontal,
        vertical,
    }
}
typedef internal_myEnum_e myEnum_e;

Then a given enum is referenced as 然后将给定的枚举引用为

myEnum_e val = myEnum::horizontal;

Hopefully there's a better way of doing this but so far, that's the only solution I found. 希望有更好的方法,但到目前为止,这是我找到的唯一解决方案。

It appears there isn't a simple solution. 似乎没有一个简单的解决方案。 Bothers me too. 也困扰我。 If you are allowed to change A there is a solution that doesn't depend on namespaces if inctoduction of the enum to a scope outside A is not desired. 如果允许更改A,则如果不需要将枚举内容发送到A外的作用域,则可以使用不依赖于名称空间的解决方案。 In contrast to using namespaces both A and A_Enum can be nested classes. 与使用命名空间相反,A和A_Enum都可以是嵌套类。

struct A_Enum
{
    enum A_enum
    {
        E0,
        E1,
        E2
    };
};

struct A : public A_Enum
{
    using A_Enum::A_enum;
};

struct B : public::A_Enum
{
    using A_Enum::A_enum; // original enum name
    bool testA(A_enum val) { return (val == E1); }
};

EDIT2: removed second solution again, doesn't work as I thought. EDIT2:再次删除第二个解决方案,不能像我想象的那样工作。

I've had the same issue in the past, and this is how I've fixed it. 我过去也遇到过同样的问题,这就是我修复它的方法。 I wanted to be able to switch the implementation of a library at compile time. 我希望能够在编译时切换库的实现。 One of the lib was using code like this: 其中一个lib使用这样的代码:

namespace Lib1 
{
  enum LibEnum { One, Two, Three };
  [...]
  void someFunc(LibEnum val);
}

In my code, I wanted to hide the library implementation from the user experience (so a user of my code should never see what lib I'm using internally): 在我的代码中,我想从用户体验中隐藏库实现(因此我的代码的用户永远不应该看到我在内部使用的lib):

Solution 1: 解决方案1:

namespace MyCode 
{
  // Example to avoid copying a function from Lib1 here
  typedef Lib1::someFunc aFunctionImUsing;

  // This doesn't work
  // typedef LibEnum MyEnum; 
  // As such code doesn't compile:
  // aFunctionImUsing(One); // Error unknown identifier One
  // But this did:
  struct Type
  {
     enum MyType { One = Lib1::One, Two = Lib1::Two, Three = Lib1::Three };
  }
  static inline Lib1::LibEnum as(Type::MyType t) { return (Lib1::LibEnum)t; }

  // Now code like this compiles:
  aFunctionImUsing(as(Type::One));
  // This one doesn't:
  // aFunctionImUsing(Type::One); // Can't convert from Type::MyType to Lib1::LibEnum

  [...]
}

Solution 2: 解决方案2:

namespace MyCode 
{
  struct Type
  {
     enum MyType { One = Lib1::One, Two = Lib1::Two, Three = Lib1::Three };
  }

  // If you don't care about polluting your namespace with numerous wrapper 
  // you can write this instead of typedef someFunc:
  static inline void myFunc(Type::MyType t) { return Lib1::someFunc((Lib1::LibEnum)t); }

  // This one does:
  myFunc(Type::One); 
  [...]
}

They are 2 issues with the code fragment above. 它们与上面的代码片段有2个问题。 The first issue is that you must copy & paste the enum inside your namespace, (but with a simple regular expression in find&replace, you're done). 第一个问题是你必须在你的命名空间中复制并粘贴枚举(但是在find和replace中使用简单的正则表达式,你就完成了)。 The second issue is that your user will have to use the "as" method, which means that it's not straightforward, or you have to wrap the method/function using the second solution. 第二个问题是你的用户必须使用“as”方法,这意味着它不是直截了当的,或者你必须使用第二个解决方案包装方法/函数。

Anyway, as it's not possible to inject an enum across namespace, this solution is the best you can do. 无论如何,因为不可能在命名空间中注入枚举,所以这个解决方案是你能做的最好的。 Notice that your code user don't even know you're using the Lib1 library in the example code. 请注意,您的代码用户甚至不知道您在示例代码中使用了Lib1库。

I had the same problem, and I used this solution instead of screwing around with superfluous namespaces. 我有同样的问题,我使用这个解决方案,而不是使用多余的命名空间。 It keeps the enum safely hidden inside the class and its explicit users. 它使枚举安全地隐藏在类及其显式用户中。

class TreeWindow abstract {
public:
  enum CheckState { On, Off, Partial }
};

class TreeControl abstract {
public:
  class ItemChecked abstract: public TreeWindow { // this is the hack needed
  public:
    using TreeWindow::CheckState;
  };

  void func(ItemChecked::CheckState);
};

TreeControl& tree = ...
tree.func(TreeControl::ItemChecked::Partial);

Why do you even have the test method in struct B? 为什么你甚至在struct B中有测试方法? I don't think it makes any sense. 我认为这没有任何意义。

By defining struct A and defining an enum inside it, you are more or less saying that "here's an enum in scope of struct A" and this is the same as saying "if you want to use this enum, you have to refer to the struct A". 通过定义结构A并在其中定义枚举,你或多或少地说“这是结构A范围内的枚举”,这与说“如果你想使用这个枚举,你必须参考结构A“。

Putting the enum inside a namespace will not solve your problem. 将枚举放在命名空间内不会解决您的问题。 Because you will have the same scope problem (C4482) 因为你会有相同的范围问题(C4482)

I think you are making things too complicated. 我觉得你做得太复杂了。 What do you think of this? 你觉得这怎么样?

struct A
{
    enum A_enum
    {
        E0,
        E1,
        E2
    };

    static bool test(A_enum val)
    {
        return (val == E1);
    }
};


int main()
{
    assert(A::test(A::E1));
    return 0;
}

Note that A::test() is static. 请注意,A :: test()是静态的。 It should be because you aren't operating on the struct state. 应该是因为你没有在struct状态下运行。 And since it's static, you dont need an instance of A to call the method. 因为它是静态的,所以你不需要A的实例来调用该方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM