2010-08-13 37 views
11

Tôi có một loại được liệt kê StackID và tôi đang sử dụng kiểu liệt kê để tham chiếu đến chỉ mục của một vectơ cụ thể và làm cho mã của tôi dễ đọc hơn.Tại sao tôi không thể tăng biến của một loại được liệt kê?

Tuy nhiên, bây giờ tôi có nhu cầu tạo biến số được gọi là nextAvail thuộc loại StackID. (nó thực sự đề cập đến một stackID cụ thể). Tôi đã cố gắng để tăng nó nhưng trong C + +, sau đây là bất hợp pháp:

nextAvail++; 

Loại nào có ý nghĩa với tôi ... bởi vì không có giới hạn kiểm tra.

Tôi có thể nhìn thấy một cái gì đó hiển nhiên, nhưng thay thế tốt là gì?


Tôi cũng muốn liên kết đến câu hỏi this.

Trả lời

16

Tôi có thể nhìn thấy một cái gì đó hiển nhiên, nhưng thay thế tốt là gì?

quá tải operator++:

// Beware, brain-compiled code ahead! 
StackID& operator++(StackID& stackID) 
{ 
#if MY_ENUMS_ARE_CONTIGUOUS && I_DO_NOT_WORRY_ABOUT_OVERFLOW 
    return stackID = static_cast<StackID>(++static_cast<int>(stackID)); 
#else 
    switch(stackID) { 
    case value1 : return stackID = value2; 
    case value2 : return stackID = value3; 
    ... 
    case valueN : return stackID = value1; 
    } 
    assert(false); 
    return stackID; // some compilers might warn otherwise 
#endif 
} 

StackID operator++(StackID& stackID, int) 
{ 
    StackID tmp(stackID); 
    ++stackID; 
    return tmp; 
} 
+0

@sbi - Nó chắc chắn sẽ làm mọi thứ đơn giản cho tôi để làm điều này. nhưng bạn nói gì với các áp phích đề nghị rằng một 'enum' có nghĩa là thể hiện một tập hợp các giá trị tùy ý? – BeeBand

+0

@BeeBand - nếu có bất kỳ việc sử dụng nào cho '++', tôi cho rằng bạn có lý do chính đáng để vượt ra ngoài việc sử dụng Enums thông thường của C++ như là các int được kiểm tra thời gian biên dịch. Mặt khác, mã của Sbi có thể làm với một số kiểm tra ràng buộc. Trong Java, enums chỉ là một loại hạng nhẹ với các thành viên không thể sửa đổi được - nó được chấp nhận thực hành để đặt các phương pháp trong đó. Xem http://download.oracle.com/javase/1.5.0/docs/guide/language/enums.html. – tucuxi

+2

@BeeBand: Tôi không đồng ý. Có lẽ năm trong mười cuốn sách giáo khoa 'enum' ví dụ là một cái gì đó giống như' enum tháng {Jan, Feb, ..., Dec}; 'và do đó một ví dụ hoàn hảo cho enenumerations có thể tăng. Trong 15 năm cuối cùng của việc thực hiện C++, tôi đã quá tải 'toán tử ++' cho các liệt kê có thể ít hơn năm lần. Nhưng tôi đã thực hiện nó. – sbi

1

Một điều tra theo ngữ nghĩa phải đại diện cho một tập hợp các giá trị liên quan, riêng biệt.

Vì vậy, bạn có thể có

enum Colour {RED, GREEN, BLUE}; 

Nhưng đó phải tương đương với:

enum Colour {GREEN, BLUE, RED}; 

Vấn đề là nếu bạn tăng một enum sau đó những cơ quan đại diện là không giống nhau. GREEN ++ trong trường hợp đầu tiên không giống như GREEN ++ trong lần thứ hai.

Làm cho chương trình của bạn phụ thuộc vào việc khai báo enum là một công thức dành cho thiên tai - người bảo trì có thể giả định rằng thứ tự của enum không quan trọng, giới thiệu nhiều lỗi thầm lặng.

+1

nhưng nó có thể để explictly gán các giá trị để enums ví dụ 'enum Màu {RED = 0, XANH = 1, BLUE = 2} '. Trong trường hợp đó, trật tự không quan trọng. – Naveen

+0

Đúng, nhưng sau đó bạn đang đi xa hơn những gì một enum nên được, và vượt qua vào nó là một tập hợp các cặp khóa/giá trị. – PaulJWilliams

+0

nó không rõ ràng những gì bạn đang đề xuất khi bạn nói "đó phải là tương đương", bạn có thể xây dựng một chút? – BeeBand

1

Enums sẽ là loại int, vì vậy bạn có thể truyền chúng. Đây có phải là những gì bạn đang cố gắng làm không?

int ndx = (int) StackID.SomeValue; 
... 
++ndx; 

Điều này sẽ làm cho ai đó rất bối rối trong dòng, tất nhiên.

Nó xảy ra với tôi rằng bạn đang sử dụng enum nơi bạn nên sử dụng const hoặc thậm chí #define. enum là thích hợp nhất khi bạn có tùy ý giá trị (trong đó giá trị chính xác không có ý nghĩa).

+0

Tôi nghĩ bạn có thể quay lại ngay. const. Mã của tôi giả định rằng giá trị chính xác là có ý nghĩa, và như bạn (và các áp phích khác) đã gợi ý, phá vỡ ý nghĩa dự định của một enum. – BeeBand

6

Đúc lui đến/từ int của khóa học là giải pháp rõ ràng, sau đó bạn thực hiện rõ ràng rằng bạn hiểu rằng việc bổ sung đang xảy ra "bên ngoài" các enum:

nextAvail = static_cast<StackID>(static_cast<int>(nextAvail) + 1); 
+2

Hmm. Vâng, đó là lựa chọn khác của tôi, tôi chỉ nghĩ rằng tất cả những diễn viên làm cho mã trông loại lộn xộn. – BeeBand

0

đối với oprator Với ++, $ 5.2 .6/1 tiểu bang- "Loại toán hạng phải là một loại số học hoặc một con trỏ đến một kiểu đối tượng hoàn chỉnh."

StackID không khớp với hóa đơn tại đây. Nó thuộc kiểu liệt kê.

Một tùy chọn là như thế này

$ 5.7/1 - "Để bổ sung, cả hai toán hạng phải có kiểu số học hoặc kiểu liệt kê, hoặc một toán hạng phải là một con trỏ đến một kiểu đối tượng được xác định hoàn toàn và một toán hạng khác phải có kiểu tách rời hoặc kiểu liệt kê."

enum Possibility {Yes, No, Maybe}; 

Possibility operator++(Possibility const& r){ 
    return Possibility(r + 1); // convert r to integer, add 1, convert back to Enum 
} 

int main(){ 
    Possibility p = Yes; 
    Possibility p1 = ++p; 
} 
+0

Nó khá rõ ràng (với các poster cũng) rằng đây là bất hợp pháp, câu hỏi là những gì thay thế tốt là –

+0

Nếu bạn quá tải __prefix__ tăng, bạn cũng nên luôn luôn quá tải __postfix__ tăng. – sbi

14

Do liệt kê không nhất thiết phải tiếp giáp. Ví dụ. lấy ví dụ này:

enum Colors { 
cRed, // = 0 
cBlue, // = 1 
cGreen = 3 
} 

Điều gì sẽ xảy ra trong trường hợp này?

Colors color = cBlue; 
Colors other = color++; 

Nếu khác là cGreen hoặc nên là 2. Trong trường hợp đó, nó không phải là thành viên điều tra hợp lệ nữa. Cái này thì sao?

Colors color = cGreen; 
Colors other = color++; 

Nên othercRed (quấn quanh) hoặc 4?

Như bạn có thể thấy, có thể tăng giá trị liệt kê giới thiệu rất nhiều câu hỏi và làm phức tạp cơ chế đơn giản mà chúng dự định.

Nếu tất cả những gì bạn quan tâm là giá trị số nguyên được tăng lên, sau đó chỉ cần truyền tới int và tăng thêm.

+2

@Igor: Bây giờ thay thế ví dụ của bạn với điều này: 'enum month ...'.Các tháng liền kề nhau và tăng tự nhiên. Vậy thì sao? – sbi

+8

@sbi: Oh tháng, điều đó thay đổi mọi thứ vì tháng rất đơn giản. . . giữ, điều gì xảy ra khi bạn tăng tháng mười hai? Nó có nên ném một ngoại lệ tràn, hay nó quấn quanh? Nó có thể là hiển nhiên đối với bạn những gì xảy ra, nhưng tôi có thể yêu cầu chức năng khác nhau. Có quá nhiều câu hỏi về cách thức * * này hoạt động, các nhà thiết kế ngôn ngữ đã chính xác không cho phép điều này và để mỗi trường hợp được xử lý riêng lẻ. –

+0

@Igor: Cảm ơn bạn! Tôi nghĩ câu trả lời của bạn cực kỳ hữu ích, tuy nhiên tôi đã chấp nhận sbi. Tôi nghĩ rằng tôi đã bị lừa một chút ở đây vì tôi về cơ bản đã hỏi 2 câu trong bài viết của tôi. Một là trong tiêu đề, và tôi nghĩ rằng bạn đóng đinh rằng trong câu trả lời của bạn và khác là dòng cuối cùng của bài viết của tôi, mà tôi nghĩ rằng các điểm đi đến sbi. – BeeBand

2

Tại sao không lưu trữ nextAvail làm int thay vào đó nếu bạn định thực hiện các phép tính số học trên đó?

Một tùy chọn khác là để bọc enum trong loại của riêng bạn và quá tải operator ++ cho nó (mà cũng có thể quấn quanh hoặc một cái gì đó ví dụ).

+0

Tôi nghĩ rằng đó là những gì tôi đang sau - gói enum trong loại của riêng tôi và sau đó tôi có thể làm những gì tôi thích nó. Bạn có thể chỉ cho tôi theo hướng của một ví dụ không? – BeeBand

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