2011-11-17 28 views
10

Tôi muốn trình biên dịch đưa ra cảnh báo như:Trình biên dịch có nên đưa ra cảnh báo nếu nhãn enum không khớp với loại không?

"Chuối không phải là màu".

Tôi hiểu rằng trong ngữ cảnh của câu lệnh chuyển đổi, các nhãn được quảng bá thành một trình biên dịch hài lòng với 0 và không quan tâm nếu nó là "Xanh" hoặc "Chuối".

Tôi đã hy vọng -Wconversion cho GCC sẽ thực hiện thủ thuật.

enum Color 
    { 
    Green = 0 
    }; 

enum Fruit 
    { 
    Banana = 0 
    }; 

int main() 
{ 
    Color c = Green; 
    switch (c) 
    { 
    case Banana: 
     std::cerr << "Banana" << std::endl; 
     break; 
    } 
    return 0; 
} 
+0

Trình biên dịch nào? – FailedDev

+3

Không có yêu cầu chẩn đoán cho nó trong 6.4.2 của C++ 11, nếu đó là những gì bạn có nghĩa là "nên trình biên dịch đưa ra một cảnh báo?". Vì vậy, câu trả lời cho câu hỏi bạn hỏi là "không", nhưng có lẽ câu hỏi bạn muốn hỏi là "có bất kỳ trình biên dịch nào trong đó tôi có thể bật cảnh báo như vậy không, và nếu như vậy thì sao?" ;-) –

+4

Ồ, và "các nhãn được quảng cáo để int" - nó không phải là khá đơn giản. Các nhãn được chuyển thành kiểu được quảng bá 'c', ít nhất là' int' và 'int' là đủ cho enum mà bạn đã xác định, nhưng nó có thể là một kiểu khác, như' unsigned int' hoặc 'long long '. –

Trả lời

17

mạnh gõ enums:

C++ 11 giới thiệu mạnh mẽ gõ enum s, sử dụng enum class:

#include <iostream> 

enum class Color 
    { 
    Green = 0 
    }; 

enum class Fruit 
    { 
    Banana = 0 
    }; 


int main() { 
    Color c = Color::Green; 
    switch (c) 
    { 
    case Fruit::Banana: 
     std::cerr << "Banana" << std::endl; 
     break; 
    } 
    return 0; 

} 

Mã này sẽ thất bại chính xác như bạn hy vọng:

test.cc:18:17: error: could not convert '(Fruit)0' from 'Fruit' to 'Color'

Lưu ý: enum class không gây GreenBanana được trong không gian tên kèm theo nữa, vì vậy bạn phải viết một cách rõ ràng Color::Fruit:: bây giờ, nhưng bạn làm cũng được typesafety.


Những vấn đề cảnh báo trong C++ 03

Tôi không nghĩ rằng cảnh báo về vấn đề này trong C++ 03 sẽ làm cho nhiều ý nghĩa, nó sẽ trở thành cơ bản chỉ là tiếng ồn.

Mọi người sử dụng enum s làm hằng số thời gian biên dịch khá thường xuyên, ngay cả đối với những thứ như trường bit. Để cảnh báo có ý nghĩa, bạn phải nắm bắt những thứ như enum { foo=0xf }; int c = foo; và nhiều mã cổ phiếu được phân tán với các chuyển đổi int/enum. (Cho phép điều này sẽ đánh bại điểm của bất kỳ kiểm tra loại mạnh hơn).

Tệ hơn nữa mặc dù sẽ được enum s được sử dụng trong hầu hết các loại bối cảnh lập trình meta, nơi vô danh enum s không chỉ được sử dụng một cách tự do thay thế cho nhau với int loại một cách thường xuyên:

template <int I> 
struct is_odd { 
    enum { value = !(I % 2) }; 
}; 

template <int I> 
struct foo { 
    static void bar() { /* I is true */ } 
}; 

template <> 
struct foo<0> { 
    static void bar() { /* I is false */ } 
}; 

int main() { 
    foo<is_odd<201>::value>::bar(); 
    int i = is_odd<200>::value; 
} 

nhưng chúng cũng sử dụng đệ quy như lưu trữ địa phương:

template <int N> 
struct factorial { 
    enum { 
     // This enum is *not* compatible with the one in N-1 
     value = N * factorial<N - 1>::value 
    }; 
}; 

template <> 
struct factorial<0> { 
    enum { value = 1 }; 
}; 

Đó là một phần lý do tại sao enum class đã được yêu cầu để giới thiệu một cách không bẻ addin g loại an toàn trên trạng thái hiện tại của enum s trong C++. Sẽ có rất nhiều cảnh báo từ mã hiện tại rằng một cảnh báo sẽ là vô dụng vì những thứ như thế này.

Ngay cả trong ví dụ câu lệnh switch khá đơn giản, bạn cho thấy, một cái gì đó như thế này là hợp pháp:

#include <iostream> 
enum Color { Green = 0x1, Red = 0x2 }; 
enum Fruit { Banana = 0x3 }; 

int main() { 
    int v = Green|Red; 
    Color c = Color(v); 
    switch (c) { 
    case Banana: 
    std::cerr << "Banana" << std::endl; 
    break; 
    } 
    return 0; 
} 

Mặc dù đây là quy phạm pháp luật ở đây nó không vô cùng có ý nghĩa, nhưng những thứ như được sử dụng khá thường xuyên và có ý nghĩa trong " bit-twiddling "C mã vẫn còn. Điểm của ví dụ này là bằng cách cho phép một số int < ->enum chuyển đổi ở bất kỳ đâu nó có nghĩa là nghiêm ngặt về loại enum sau này sẽ được hiển thị vô nghĩa. Trong trường hợp chung, bạn không thể phát hiện xem loại chuyển đổi này có xảy ra hay không (nó có thể có trong một đơn vị dịch thuật khác).

enum class là cách tốt nhất để giới thiệu độ chặt chẽ như vậy một cách rõ ràng mà không ảnh hưởng xấu đến mã hiện có.

+0

Tôi nghĩ rằng bạn đã thêm một số điểm hợp lệ ở đây, tuy nhiên tôi không thấy lý do tại sao một cảnh báo trong ngữ cảnh của câu lệnh chuyển đổi sẽ không hữu ích. –

+0

@EddyPronk - Tôi đã thực hiện một chỉnh sửa khác, mà tôi hy vọng cho thấy lý do tại sao chỉ cho phép chuyển đổi intum> làm cho các cảnh báo như vậy không hữu ích. – Flexo

+0

Tôi thích 'enum class' nhưng sẽ mất nhiều năm trước khi tôi có thể sử dụng C++ 11 tính năng trong cuộc sống thực. Bạn đã thêm nhiều hơn về chuyển đổi, có liên quan nhưng không liên quan đến trường hợp cụ thể mà tôi hỏi. Một lần nữa, trong bối cảnh cụ thể của một tuyên bố chuyển đổi nó sẽ có ý nghĩa để cảnh báo về thực tế là chúng tôi chuyển sang loại màu và có một nhãn trường hợp của loại trái cây. Nên có đủ ngữ cảnh để cảnh báo về một thứ gì đó ở đây. –

6

Trong C++ 11 (tiêu chuẩn C++ mới), bạn có thể sử dụng enum class để tạo một enum được nhập mạnh mẽ. Xem Wikipedia article on C++11.

Ví dụ:

enum class Color { Green }; 
enum class Fruit { Banana }; 

// Put your main here - it would now fail 
+0

Trình chuyển đổi có hoạt động ngay bây giờ không? Tôi đoán là không. –

+0

Không, đừng bận tâm, "loại liệt kê" được cho phép rõ ràng dưới dạng mục tiêu chuyển đổi. :) –

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