2012-02-08 34 views
10

Dưới đây là một chút mã mà có vẻ như nó sẽ làm việc:Tại sao C++ số_limits <enum_type> :: max() == 0?

#include <cassert> 
#include <limits> 

enum test { A = 1 }; 

int main() 
{ 
    int max = std::numeric_limits<test>::max(); 
    assert(max > 0); 
} 

Nhưng nó không dưới cả GCC (4.6.2) và kêu vang (2.9) trên Linux: max() với nhiều loại enum là trong thực tế số không! Và điều này vẫn đúng ngay cả khi bạn sử dụng trình chỉ định loại C++ 11 enum để giải thích kiểu bạn muốn enum của bạn có.

Tại sao điều này? Và đối với hành vi C++ 11, nó có phải là một cái gì đó được gọi một cách khéo léo không? Tôi có thể tìm thấy không có đề cập đến nó trong N2347, bài báo trên Strongly Typed Enums.

+1

gì bạn mong đợi giá trị được? –

+1

Kết quả của is_specialized là gì? – RaptorFactor

+0

@JamesMcNellis: Tôi cho rằng anh ta dự kiến ​​nó giống như số_limits :: max. – RaptorFactor

Trả lời

22

std::numeric_limits chuyên về Thư viện chuẩn "cho từng loại số học, cả dấu phẩy động và số nguyên, bao gồm bool" (§18.3.2.1/2).

Điều tra của bạn test không phải là một trong các loại này, vì vậy mẫu chính được sử dụng. Hành vi của nó được xác định bởi §18.3.2.3/1: "Mẫu numeric_limits<T> mặc định phải có tất cả các thành viên, nhưng với các giá trị 0 hoặc false."

Nếu bạn muốn biết các đặc điểm của các loại cơ bản của test, bạn có thể sử dụng underlying_type:

std::numeric_limits<std::underlying_type<test>::type>::max() 

Ngoài ra, bạn có thể chuyên numeric_limits cho test và có nó trả lại giá trị bạn muốn. Đây không phải là một ý tưởng đặc biệt tốt.

+1

Tại sao không chuyên về ý tưởng hay? –

+1

@RobKennedy: Thật lạ lùng nhất và gây hiểu lầm tồi tệ nhất. Bạn không thể chuyên nó một lần cho tất cả các enums (vì có enums trong thư viện chuẩn), vì vậy bạn sẽ phải chuyên nó cho mỗi enum cá nhân. Sau đó, các giá trị nên là gì? Bạn không thể thực sự trì hoãn 'inner_type' trực tiếp vì giá trị tối đa đại diện bởi kiểu cơ bản không nhất thiết là giá trị tối đa đại diện cho enum (ví dụ, nếu' test' được biểu diễn bằng 'int', giá trị' int' tối đa có lẽ là '2^32-1', nhưng giá trị' test' tối đa là '1'. –

+3

Tại sao bất cứ ai thậm chí muốn chuyên nó một lần cho tất cả các enums? Thông thường, người ta sẽ quan tâm đến một chuyên môn cho bài kiểm tra' đặc biệt này "enum. Sẽ không có bất cứ điều gì sai trái với điều đó, phải không? – jrok

2

Đối với các phiên bản mẫu không chuyên biệt, max trả về T(). Bạn chưa viết chuyên môn numeric_limits cho loại test của mình, do đó bạn sẽ được triển khai mặc định.

1

numeric_limits<T> là mẫu lớp thông thường, nó không được kết nối với trình biên dịch theo bất kỳ cách đặc biệt nào để tìm hiểu về các loại enum do người dùng xác định. Nếu bạn xem tệp <limits>, tệp có định nghĩa mẫu mặc định trả về số không cho mọi thứ và toàn bộ các chi tiết kỹ thuật loại cụ thể cho từng loại riêng lẻ, trả về các hằng số phù hợp.

Bạn có thể "cắm" enum vào numeric_limits bằng cách cung cấp đặc điểm kỹ thuật của chính mình numeric_limits<test>. Bạn có thể sao chép cho int từ <limits> và sửa đổi nó cho phù hợp với nhu cầu của bạn.

1

Từ dự thảo C++ 11:

Trong 18.3.2.1, khoảng numeric_limits:

loại tiêu chuẩn

Non-số học, chẳng hạn như phức tạp (26.4.2), không phải chuyên ngành.

Và enum không phải là loại chuẩn số học.

Sau đó, trong bản mẫu không chuyên:

template<class T> class numeric_limits { 
    public: 
    [...] 
    static constexpr bool is_specialized = false; 
    static constexpr T max() noexcept { return T(); } 
}; 

Đó là, không chuyên max() chức năng trả về giá trị mặc định khởi tạo cho loại đó, có nghĩa là 0.

+0

Một enum thực sự không phải là một loại tiêu chuẩn số học, nhưng điều đó không có nghĩa đó là một loại tiêu chuẩn phi số học. Nó không phải bất kỳ loại tiêu chuẩn nào cả. –

+0

@RobKennedy - Oh! Bạn đúng rồi! Đoạn đó có nghĩa là không có gì trong ngữ cảnh này. Nhưng điều đó không thay đổi điểm chính: rằng 'numeric_limits' không dành riêng cho các loại enum. – rodrigo

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