2012-09-05 25 views
7

Chỉ để xem cách nó hoạt động, tôi đã xem xét việc triển khai libstdC++ std::common_type trong tiêu đề type_traits. Tôi phải thừa nhận rằng tôi không thực sự hiểu nó hoạt động như thế nào. Dưới đây là:std :: common_type implementation

/// common_type 
template<typename... _Tp> 
    struct common_type; 

template<typename _Tp> 
    struct common_type<_Tp> 
    { typedef _Tp type; }; 

template<typename _Tp, typename _Up> 
    struct common_type<_Tp, _Up> 
    { typedef decltype(true ? declval<_Tp>() : declval<_Up>()) type; }; 

template<typename _Tp, typename _Up, typename... _Vp> 
    struct common_type<_Tp, _Up, _Vp...> 
    { 
     typedef typename 
     common_type<typename common_type<_Tp, _Up>::type, _Vp...>::type type; 
    }; 

Tôi hiểu rõ cách khai báo đầu tiên, thứ hai và thứ tư hoạt động như thế nào. Tuy nhiên, tôi không thể hiểu cách khai báo thứ ba hoạt động như thế nào. Ai đó có thể cố gắng giải thích cơ chế được sử dụng ở đây?

Trả lời

8

Trước hết, std::declval<T>() mang lại giá trị r của loại T. Cố gắng làm bất cứ điều gì với giá trị sẽ thất bại vì vậy nó chỉ có thể được sử dụng trong một bối cảnh không được đánh giá. Tiếp theo, toán tử ternary suy ra kiểu của nó như là kiểu dữ liệu chuyên dụng nhất chung cho cả hai đối số (nếu không có kiểu như vậy, nó không thành công). Vì vậy, các loại biểu thức

true? declval<T0>(): declval<T1>() 

là loại chuyên dụng nhất chung của T0T1. Tất cả những gì còn lại là biến biểu thức này thành một loại và đảm bảo rằng nó không được đánh giá. decltype(expr) chỉ thực hiện việc này. Rõ ràng, hai phiên bản đối số của thịt bò của logic: những người khác đang có để đối phó với các trường hợp góc (một đối số) và để tận dụng hai phiên bản đối số để mang lại loại phổ biến của các loại tùy ý.

3

Phiên bản thứ ba sử dụng toán tử điều kiện có điều kiện để xác định loại phổ biến. Các quy tắc của nó được mô tả khá dài trong phần 5.16 của tiêu chuẩn, vì vậy tôi không chắc tôi nên sao chép chúng ở đây.

một cách đơn giản, khái niệm:

boolean-expression ? second-operand : third-operand 

có một "loại phổ biến" của toán hạng thứ hai và thứ ba, nếu như vậy tồn tại. Sau đó, thông số decltype được sử dụng để "chuyển đổi" biểu thức thành một loại-specifier.

+3

+1, một bài đọc hay về * ma thuật * bao gồm cả toán tử bậc ba: [Tình trạng có điều kiện: FOREACH redux] (http://www.artima.com/cppsource/foreach.html) –

+0

Ok, tôi nghĩ cuối cùng tôi cũng có lừa. Vì vậy, nó dựa vào thực tế là toán tử bậc ba suy ra các kiểu trả về của nó dựa trên các toán hạng của nó. Nó không nghĩ về điều đó. Cảm ơn! – Morwenn

1

Câu chuyện dài ngắn: Trình cắt đang tạo trình biên dịch C++ xác định loại tổ tiên gần nhất cho nó.

Nhà điều hành đại học có loại kết quả tĩnh của tổ tiên gần nhất của hai biểu thức có thể.

ví dụ:

Một kế thừa từ B

X thừa hưởng từ Y thừa hưởng từ B

<expression> ? <expression with static type A> : <expression with static type X> 
    = <expression with static type B> // this is how the C++ parser sees it 

Đây là cách thức hoạt động ngôn ngữ C++. Các decltype chỉ làm cho typedef là loại tĩnh của kết quả của biểu thức đó (bất kỳ loại trình biên dịch C++ xác định nó là)

+0

Điều này hơi gây nhầm lẫn trong việc sử dụng các cụm từ * tổ tiên * và trong ví dụ sử dụng thừa kế. Chắc chắn nó làm điều đó, nhưng nó làm nhiều hơn nữa, nếu một trong các loại là * convertible * sang cái kia, nó sẽ chọn kiểu thứ hai, ví dụ '(true? 1, 1.)' có kiểu 'double' là' int' có thể chuyển đổi thành gấp đôi, mặc dù không có * tổ tiên * hoặc * thừa kế *. –

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