2009-05-23 31 views
10

Vì vậy, đây là vấn đề của tôi:C++ typedef enum của lớp khác?

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

Tôi đặc biệt không muốn nói A::E1. Nếu tôi thử B_enum::E1 tôi nhận được cảnh báo rằng nó không chuẩn. Có cách nào tốt để làm một cái gì đó như thế này?

+2

"Tôi đặc biệt không muốn nói A :: E1" - tại sao không? –

+1

vì A được sử dụng trong một số lớp và tôi không muốn tham chiếu đến loại không liên quan. Trong thực tế sử dụng của tôi, A là một kiểu lồng nhau được đánh máy ở một nơi khác, và nó thực sự sẽ giống như N :: E :: C :: A :: E1 – rlbond

+0

Sau đó, bạn sẽ phải tạo một không gian tên và xác định enum đó. Tại sao không làm điều đó? –

Trả lời

3

Tôi cho rằng A phải là không gian tên thay vì cấu trúc.

+0

Vâng A cũng có những thứ khác, nhưng có lẽ sẽ tốt hơn nếu đặt nó vào một không gian tên. – rlbond

+1

Bạn cũng có thể xác định một enum ở phạm vi toàn cầu ... hoặc, trong một lớp cơ sở được thừa kế bởi các lớp sử dụng nó. – ChrisW

-2

Tại sao bạn thậm chí có phương pháp thử nghiệm trong cấu trúc B? Tôi không nghĩ nó có ý nghĩa gì cả.

Bằng cách xác định cấu trúc A và xác định một enum bên trong nó để tham khảo cấu trúc A ".

Đặt enum bên trong một không gian tên sẽ không giải quyết được sự cố của bạn. Vì bạn sẽ có cùng một vấn đề phạm vi (C4482)

Tôi nghĩ bạn đang làm mọi thứ quá phức tạp. Bạn nghĩ gì về điều này?

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

Lưu ý rằng A :: test() là tĩnh. Nó phải là vì bạn không hoạt động trên trạng thái struct. Và vì nó là tĩnh, bạn không cần một thể hiện của A để gọi phương thức.

+1

Đó là một ví dụ. Trường hợp thực sự phức tạp hơn. Không, tôi không thể làm theo cách đó. – rlbond

2

Đặt enum trong phạm vi toàn cầu là quá tiếp xúc, đặt chúng trong một lớp học có thể giới thiệu phụ thuộc không mong muốn. Đối với enum không chặt chẽ liên kết đến một lớp học, đây là những gì tôi sử dụng:

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

Sau đó, bạn có thể sử dụng, ở phạm vi toàn cầu:

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

Đó là nhiều hay ít bắt chước C# cách xử lý phạm vi enums . Preprocessor sẽ sản xuất mã này:

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

Sau đó, một enum cụ thể được tham chiếu như

myEnum_e val = myEnum::horizontal; 

Hy vọng rằng có một cách tốt hơn để làm điều này nhưng cho đến nay, đó là giải pháp duy nhất tôi tìm thấy.

+0

Khi C++ 0x sẽ đến ... bất cứ khi nào điều này sẽ ... sẽ có "enum class MyEnum {...};" hoạt động giống như C# enum (với các giá trị enum trong "không gian tên" riêng). Thật vậy, cú pháp được lấy từ C++ /. CLI (.NET C++), nơi nó được sử dụng để phát ra các enums .NET. – mmmmmmmm

+0

Làm thế nào để bạn tham khảo các yếu tố sau đó? – rlbond

+0

bạn có thể nói EnumName :: Enumerator và cũng có thể khai báo chúng ở một nơi khác bằng cách sử dụng khai báo sử dụng như "using EnumName :: Enumerator;" để hiển thị mà không cần thêm tiền tố với EnumName ::. tuy nhiên, điều này đi kèm với đặc tả kiểu cơ bản mới. cho "lớp enum", mặc định là int. Bạn có thể thay đổi nó bằng "enum class EnumName: IntegerType {...};" và các công trình tương tự của khóa học cũng cho enums unscoped "enum EnumName: int {...}", trong đó không có mặc định. Cùng với đó, khả năng "tuyên bố về phía trước" cũng xuất hiện: "enum EnumName: int;". –

0

Tôi đã gặp sự cố tương tự trong quá khứ và đây là cách tôi đã khắc phục sự cố đó. Tôi muốn có thể chuyển đổi việc triển khai thư viện lúc biên dịch. Một trong những lib được sử dụng mã như thế này:

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

Trong mã của tôi, tôi muốn che giấu việc thực hiện thư viện từ kinh nghiệm người dùng (do đó, một người sử dụng của mã của tôi không bao giờ nên xem những gì lib Tôi đang sử dụng trong nội bộ):

giải pháp 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 

    [...] 
} 

giải pháp 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); 
    [...] 
} 

Chúng là 2 vấn đề với đoạn mã ở trên.Vấn đề đầu tiên là bạn phải sao chép & dán enum bên trong không gian tên của bạn, (nhưng với một biểu thức chính quy đơn giản trong tìm thấy & thay thế, bạn đã hoàn tất). Vấn đề thứ hai là người dùng của bạn sẽ phải sử dụng phương thức "as", có nghĩa là nó không đơn giản, hoặc bạn phải bọc phương thức/hàm bằng cách sử dụng giải pháp thứ hai.

Dù sao, vì không thể tiêm một enum qua không gian tên, giải pháp này là tốt nhất bạn có thể làm. Lưu ý rằng người dùng mã của bạn thậm chí không biết bạn đang sử dụng thư viện Lib1 trong mã ví dụ.

0

Tôi đã gặp vấn đề tương tự và tôi đã sử dụng giải pháp này thay vì vặn vẹo xung quanh với các không gian tên thừa. Nó giữ enum an toàn ẩn bên trong lớp và người dùng rõ ràng của nó.

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); 
+4

Tôi nghĩ đây là ngôn ngữ sai ... – rlbond

0

Dường như không có giải pháp đơn giản. Bothers me too. Nếu bạn được phép thay đổi A, có một giải pháp không phụ thuộc vào không gian tên nếu bạn không muốn điều chỉnh enum thành phạm vi bên ngoài A. Trái ngược với việc sử dụng các không gian tên cả A và A_Enum có thể là các lớp lồng nhau.

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: gỡ bỏ giải pháp thứ hai lần nữa, không hoạt động như tôi nghĩ.

Các vấn đề liên quan