2012-04-26 60 views
11

Tôi có một API C định nghĩa một enum như vậy:Sử dụng enums C cờ trong C++

typedef enum 
{ 
    C_ENUM_VALUE_NONE = 0, 
    C_ENUM_VALUE_APPLE = (1 << 0), 
    C_ENUM_VALUE_BANANA = (1 << 1), 
    C_ENUM_VALUE_COCONUT = (1 << 2), 
    // etc. 
    C_ENUM_VALUE_ANY  = ~0 
} CEnumType; 

Có một phương pháp có sử dụng enum, định nghĩa là:

void do_something(CEnumType types); 

Trong C, bạn có thể gọi một cái gì đó như:

do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA); 

Tuy nhiên, nếu bạn cố gắng gọi nó theo cách này trong C++ (Linux, g ++ biên dịch), bạn nhận được một lỗi, chuyển đổi không hợp lệ từ ‘int’ thành ‘CEnumType’.

Cách chính xác để sử dụng API C này từ ứng dụng C++ của tôi là gì?

Trả lời

22

Bạn cần phải cast int s enums trong C++, nhưng bạn có thể ẩn các diễn viên trong một nhà điều hành tùy chỉnh OR:

CEnumType operator|(CEnumType lhs, CEnumType rhs) { 
    return (CEnumType) ((int)lhs| (int)rhs); 
} 

Với toán tử này tại chỗ, bạn có thể viết của bạn gốc

do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA); 

và nó sẽ biên dịch và chạy mà không gặp sự cố.

+3

+1 cho sự thông minh của quá tải toán tử' | '! –

+2

Nó thậm chí còn được xác định hành vi để có một đối tượng của loại enum có giá trị không phải là một trong các giá trị enum quy định? – bames53

+0

Tôi khá chắc chắn toàn bộ (int) chuyển đổi này là thừa vì enum của bạn có một số loại lưu trữ đã có hoặc có thể được xác định với enum X: int {} – Andy

0

Bằng cách nhập hai giá trị enum, bạn đang tạo một giá trị không hợp lệ (0x3 không nằm trong loại CEnumType enum). Số đếm không phải là bitfields. Nếu bạn muốn một bitfield, hãy xác định một bit.

Bạn có thể truyền giá trị nếu bạn muốn ép buộc nó, nhưng điều đó có thể gây ngạc nhiên cho một số mã đang đếm chỉ có thể nhận được các giá trị được liệt kê.

do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA)); 
+1

Anh ấy không định nghĩa giao diện này, anh ấy đang sử dụng giao diện được xác định bởi người khác được thiết kế cho C. Có lẽ anh ấy không thể (và không nên) thay đổi mã thư viện. – dsharlet

+0

Enum có đơn giản khai báo, và hàm đang chấp nhận enum chỉ để gợi ý nhà phát triển C nơi tìm kiếm các giá trị có thể được xored để tạo thành đầu vào ... Không có gì sai với điều đó, chỉ là một cách suy nghĩ khác. Giống như C chứ không phải C++. –

+1

"* Bằng cách nhập hai giá trị enum, bạn đang tạo một giá trị không hợp lệ (0x3 không nằm trong enum CEnumType) *" Tôi nghĩ rằng điều này là sai. Nó chỉ vì toán tử bit-wise đánh giá int và do đó là lỗi. Không phải vì nó được đánh giá là 0x3 mà không có trong enum –

6

C++ có quy tắc nghiêm ngặt hơn C về enums. Bạn sẽ cần phải cast giá trị cho các kiểu enumeration khi gọi:

do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA)); 

Ngoài ra, bạn có thể viết một hàm wrapper mà phải mất một int để làm diễn viên cho bạn, nếu bạn muốn tránh bằng văn bản cho dàn diễn viên hàng khi bạn gọi nó là:

void do_something_wrapper(int types) 
{ 
    do_something((CEnumType)types); 
} 
... 
do_something_wrapper(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA); 

Mặc dù tôi không biết nếu tôi muốn xem những gì bạn nhận được khi bạn vượt qua một quả táo với một quả chuối ...

5

trong trường hợp hoạt động Bitwise, khái niệm đánh giá thành kiểu nguyên thủy, tức là int, long, v.v. Tuy nhiên, hàm của bạn có một kiểu không nguyên thủy (CEnumType). Cách duy nhất tôi biết để vượt qua điều này là để diễn tả các biểu thức. Ví dụ:

do_something((CEnumType) (C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA)); 
+0

+1 để ghi chú đánh giá biểu thức thành 'int'. do_something (C_ENUM_VALUE_APPLE) sẽ hoạt động tốt mà không có bất kỳ phôi nào. Bởi vì biểu thức được đánh giá thành một 'int' mà một diễn viên được yêu cầu –

1

CEnumType A;

A = (CEnumType) (A | C_ENUM_VALUE_APPLE);

Bạn cũng có thể sử dụng theo cách này.