2012-02-26 35 views
20

Tôi đang sử dụng một enum scoped để liệt kê các tiểu bang trong một số máy nhà nước mà tôi đang thực hiện. Ví dụ, chúng ta hãy nói điều gì đó như:Tương đương với "sử dụng không gian tên X" để liệt kê phạm vi?

enum class CatState 
{ 
    sleeping, 
    napping, 
    resting 
}; 

Trong tập tin cpp tôi, nơi tôi định nghĩa một bảng chuyển trạng thái, tôi muốn sử dụng một cái gì đó tương đương với using namespace X vì vậy mà tôi không cần phải thêm tiền tố tất cả các tên trạng thái của tôi với CatState::. Nói cách khác, tôi muốn sử dụng sleeping thay vì CatState::sleeping. Bảng chuyển tiếp của tôi có một vài cột, vì vậy tránh tiền tố CatState:: sẽ giữ cho mọi thứ gọn nhẹ và dễ đọc hơn.

Vì vậy, có cách nào để tránh phải nhập CatState:: mọi lúc không?


Yeah, yeah, tôi đã nhận thức được những cạm bẫy của using namespace. Nếu có tương đương với các enums mạnh mẽ, tôi hứa sẽ chỉ sử dụng nó trong một phạm vi giới hạn trong tệp thực thi cpp của tôi, chứ không phải cho cái ác.

+0

Bạn có thực sự cần một 'lớp enum' hoặc' enum' sẽ làm gì? – netcoder

+0

Ban đầu nó là một chữ 'enum' đơn giản, nhưng tôi đang chuyển mã của mình để sử dụng các tính năng C++ 11. Tôi thích ý tưởng về sự an toàn kiểu mạnh hơn với 'lớp enum'. –

Trả lời

11

Vì vậy, có cách nào để tránh phải nhập CatState:: mọi lúc không?

Không. Không có gì tương đương khi phải nhập ClassName:: cho thành viên lớp tĩnh. Bạn không thể nói using typename ClassName và sau đó nhận được tại internals. Điều tương tự cũng được áp dụng cho các loại enum s được nhập mạnh mẽ.

Tất nhiên, bạn không thể sử dụng cú pháp enum class, chỉ cần sử dụng thường xuyên enum s. Nhưng sau đó bạn bị đánh mạnh. Cần phải lưu ý rằng một trong những lý do để sử dụng ALL_CAPS cho các loại enum được đánh máy yếu là tránh xung đột tên. Một khi chúng ta có phạm vi đầy đủ và gõ mạnh mẽ, tên của một enum được xác định duy nhất và không thể xung đột với các tên khác. Việc có thể đưa những tên đó vào phạm vi không gian tên sẽ giới thiệu lại vấn đề này. Vì vậy, bạn có thể sẽ muốn sử dụng ALL_CAPS một lần nữa để giúp phân biệt tên.

+1

+1 Cảm ơn. Tôi đã tưởng tượng ra sự mạnh mẽ để trở thành một cái gì đó giống như một không gian tên, nhưng nghĩ về nó như một lớp (phần nào) có ý nghĩa hơn bây giờ. –

8

Bạn có thể xem xét sử dụng một typedef để rút ngắn tên tiêu chuẩn:

typedef CatState C; 

Hoặc, nếu các cột được lặp đi lặp lại trong một cách mà họ có thể được tạo ra một cách dễ dàng, bạn có thể xem xét sử dụng một macro để tạo ra mỗi hàng trong bảng, có thể dẫn đến mã rất ngắn gọn (và dễ đọc hơn).

+0

Vì vậy, bạn đang nói rằng không có tương đương với 'sử dụng không gian tên' cho enums? Nếu đó là trường hợp, sau đó một typedef ngắn có vẻ như là giải pháp tốt nhất cho tôi. –

+0

Không phải là tôi biết, không. Bạn có thể sử dụng một khai báo sử dụng cho mỗi điều tra viên (ví dụ: 'sử dụng CatState :: ngủ;', v.v.), nhưng tôi không chắc chắn 100%. Nếu mã là rất lặp đi lặp lại, mặc dù, tôi rất muốn giới thiệu một vĩ mô. –

+0

+1 Tôi đã sử dụng đề xuất typedef của bạn, nhưng Nicol đã đưa ra câu trả lời trực tiếp cho câu hỏi của tôi. Tôi ước tôi có thể chấp nhận cả hai câu trả lời. –

2

Câu trả lời của Nicol là chính xác: ngôn ngữ được thiết kế để làm cho bạn luôn đủ điều kiện điều tra phạm vi (ngoại trừ trong phạm vi enum { } chính nó).

Tuy nhiên, here is a technique Tôi đã tìm ra các điều tra "phạm vi" không được bao phủ trong các lớp đã chọn. Về mặt kỹ thuật, các điều tra viên không được kiểm duyệt, vì vậy chúng sẽ chuyển đổi hoàn toàn thành int. Tuy nhiên, trong thành ngữ chúng được truy cập bằng toán tử phạm vi sau tên enum đúng, do đó cú pháp không có sự khác biệt - và do đó nó yêu cầu C++ 11.

#define IMPORTABLE_ENUM(TYPENAME, ...) \ 
\ 
struct import_ ## TYPENAME { \ 
    enum TYPENAME { \ 
     __VA_ARGS__ \ 
    }; \ 
}; \ 
\ 
typedef import_ ## TYPENAME :: TYPENAME TYPENAME; 

// usage: 
IMPORTABLE_ENUM (duck, huey, dewey, louie) 

duck d = duck::dewey; // can't use unscoped enumerators here 

struct duck_madness : private import_duck { // but inside a derived class 
    duck who_did_it() { return huey; } // qualification is unnecessary 
}; 
2

Tôi cũng rất muốn có khả năng này và tôi thấy giới hạn khá khó chịu.Nó thường là tốt nhất để có lập trình viên quyết định các tính năng mà anh ta muốn sử dụng. Hoặc là phạm vi rõ ràng hoặc cách thuận tiện hơn. Nếu bạn hạn chế các lập trình viên, anh ta hoặc là sẽ thả toàn bộ tính năng vì lợi ích của việc tạo thuận tiện hoặc tạo ra các cách giải quyết xấu, giống như kiểu sau dựa trên kiểu an toàn enum. Nó sẽ có một số chi phí khi biên dịch mà không tối ưu hóa.

template<class _Enum> 
class type_safe_enum 
{ 
private: 
    _Enum m_EnumValue; 
    operator int(); 
public: 
    inline operator _Enum() const { return m_EnumValue; } 
    inline void operator =(_Enum x) { m_EnumValue = x; } 
}; 

enum _MY_ENUM 
{ 
    Value1, 
    Value2 
}; 

enum _MY_ENUM2 
{ 
    Value3, 
    Value4 
}; 

typedef type_safe_enum<_MY_ENUM> MY_ENUM; 

void TestMyEnum() 
{ 
    MY_ENUM myEnum; 
    int x; 

    myEnum = Value1; // ok 
    // myEnum = Value3; // compilation error 
    // myEnum = 0; // compilation error 
    // x = myEnum; // compilation error 

} 
+1

Các ký hiệu '_Enum' và' _ [A-Z] + 'khác của bạn dẫn đến hành vi không xác định, xem [quy tắc về gạch dưới] (http://stackoverflow.com/a/228797/673852). Cụ thể, 'Tất cả các số nhận dạng bắt đầu bằng dấu gạch dưới và một chữ hoa hoặc một dấu gạch dưới khác luôn được dành riêng cho bất kỳ việc sử dụng nào''; 'Nếu chương trình khai báo hoặc định nghĩa một định danh trong một ngữ cảnh mà nó được đặt trước <...>, hành vi là không xác định.'. – Ruslan

+0

Tôi đoán bạn không phải từ thế giới Windows, nếu không bạn sẽ biết rằng MS vi phạm tiêu chuẩn đó với hầu hết các thẻ cấu trúc của chúng. Tôi đã không nói, sử dụng mã này vì nó là dành cho dự án cá nhân của bạn. Các định danh này được dành riêng để các lập trình viên * bình thường * có các quy tắc mà chúng có thể theo dõi và không xung đột với các nhà phát triển hệ thống. Chúng được dành riêng cho các nhà phát triển hệ thống và dickheads điên điên như tôi, những người làm công cụ riêng của họ. Tôi viết tiêu đề hệ thống, bộ nạp khởi động và hạt nhân hệ điều hành, vì vậy các quy tắc này không dành cho tôi. Điều tồi tệ hơn là vi phạm quy tắc này là sử dụng các hàm C chuẩn như strcpy hoặc asctime. – Timo

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