2012-01-21 33 views
17

§20.2.4 [declval]Tại sao 'declval' được chỉ định theo 'add_rvalue_reference <T> :: type' và không phải 'T &&'?

template <class T> 
typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand 

Tại sao sử dụng add_rvalue_reference đây?

Từ §20.9.7.2 [meta.trans.ref] trên add_rvalue_reference:

Nếu T tên một đối tượng hoặc chức năng loại sau đó các thành viên typedef type sẽ đặt tên T&&; nếu không, type sẽ có tên T. [Lưu ý: Quy tắc này phản ánh ngữ nghĩa của việc thu gọn tham chiếu (8.3.2). Ví dụ: khi một loại T tên là loại T1&, loại add_rvalue_reference<T>::type không phải là tham chiếu rvalue. -end lưu ý]

Kể từ add_rvalue_reference là có nghĩa là để phản ánh tham khảo sụp đổ dù sao, tại sao không chỉ cần sử dụng T&& như sau?

template<class T> 
T&& declval(); 

Điều gì có thể xảy ra? Sự khác biệt chính xác giữa hai phiên bản là gì?

+1

"Điều gì có thể xảy ra sai?" Con vịt! –

+3

@LightnessRacesinOrbit: Err .. cái gì? Chỉ vì tôi bỏ qua một cái gì đó tôi nhận được -1? Thú vị ... – Xeo

+1

@Lightness Now _that_ là vô nghĩa. –

Trả lời

14

Tôi không biết đây có phải là lý do thực tế hay không, nhưng add_rvalue_reference có hành vi khác nhau đối với void.

add_rvalue_reference<void>::type chỉ đơn giản là void.

void&& là lỗi.

+0

Oooh, tốt. Tuy nhiên, khi nào bạn thực sự muốn có một 'std :: declval ()'? Tôi chỉ có thể tưởng tượng trong một biểu thức SFINAE 'decltype (t.size(), std :: declval (), std :: true_type)' hoặc một cái gì đó, nhưng 'void()' là thuận tiện hơn nhiều và hoạt động tất cả như nhau. – Xeo

+1

@Xeo có thể trong các lớp mẫu cho phép 'void' làm mẫu param? 'mẫu lớp foo {… declval …}; foo bar; '. Điều này có thể hiếm, nhưng tốt hơn nếu nó hoạt động khi bạn không cần nó, hơn là nếu nó không hoạt động khi bạn cần nó. –

+0

Tôi sẽ chấp nhận điều này, vì nó nói rõ những gì tôi đã bỏ sót/nhìn ra: "' void && 'là một lỗi". – Xeo

10

Một số định nghĩa phụ thuộc vào declval cho kết quả hợp lý cho cv đủ điều kiệnvoid. Một ví dụ là is_assignable:

template <class T, class U> 
struct is_assignable; 

Khái niệm declval<T>() = declval<U>() nổi hình thành khi điều trị như một toán hạng unevaluated ...

Mục đích là "tốt được hình thành" đề cập đến cái giếng -formed-Ness của biểu thức phân công, và không cho dù declval<T> chính nó là tốt hình thành. I E. chúng tôi chỉ muốn lo lắng về một điều tại một thời điểm.

10

Sự khác biệt là add_rvalue_reference<> chỉ thực sự thêm phần && nếu T là một loại đối tượng hoặc chức năng. Nếu T không phải là loại đối tượng hoặc chức năng (ví dụ: void), bạn không muốn thêm &&.

Xem this example on Ideone.
This webpage of Boost's implementation giải thích:

Vai trò của hàm template declval() là sự chuyển hóa của một loại T thành một giá trị mà không sử dụng hoặc đánh giá chức năng này.Tên được cho là hướng sự chú ý của người đọc đến thực tế là biểu thức declval<T>() là một lvalue nếu và chỉ khi T là tham chiếu giá trị bằng không, nếu không thì sẽ là một giá trị. Để mở rộng lĩnh vực chức năng này chúng ta có thể làm tốt hơn một chút bằng cách thay đổi tuyên bố của mình cho

template<class T> 
typename std::add_rvalue_reference<T>::type declval(); // not used 

đảm bảo rằng chúng tôi cũng có thể sử dụng cv void như mẫu tham số.

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