简体   繁体   中英

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 . If I try B_enum::E1 I receive a warning that it is nonstandard. 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:

#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. 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. In contrast to using namespaces both A and A_Enum can be nested classes.

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.

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:

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):

Solution 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:

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. 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). 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.

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.

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? 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".

Putting the enum inside a namespace will not solve your problem. Because you will have the same scope problem (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. It should be because you aren't operating on the struct state. And since it's static, you dont need an instance of A to call the method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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