2012-01-21 105 views
17

§20.2.4 [declval]爲什麼按'add_rvalue_reference <T> :: type'而不是'T &&'指定'declval'?

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

爲什麼在這裏使用add_rvalue_reference

§20.9.7.2 [meta.trans.ref]add_rvalue_reference

如果T名稱的對象或功能類型的typedef然後將type構件應命名T&&;否則,type應命名爲T。 [注意:該規則反映了參考摺疊(8.3.2)的語義。例如,當類型T命名爲T1&類型時,類型add_rvalue_reference<T>::type不是右值引用。 末端注]

由於add_rvalue_reference是要反映出參考反正崩潰,爲什麼不直接使用T&&像下面?

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

什麼可能出錯?這兩個版本之間究竟有什麼區別?

+1

「什麼可能會出錯?」鴨! –

+3

@LightnessRacesinOrbit:呃..什麼?僅僅因爲我忽略了我得到的-1?有趣的東西... – Xeo

+1

@Lightness現在_that_是毫無意義的。 –

回答

14

我不知道這是否是實際原因,但add_rvalue_referencevoid有不同的行爲。

add_rvalue_reference<void>::type只是void

void&&是一個錯誤。

+0

Oooh,好點。但是,你什麼時候會真的想要一個'std :: declval ()'?我只能想象表達式SFINAE'decltype(t.size(),std :: declval (),std :: true_type)'或者什麼,但'void()'更方便,並且工作原理完全相同。 – Xeo

+1

@Xeo也許在允許'void'作爲模板參數的模板類中? 'template class foo {... declval ...}; foo bar;'。這可能很少見,但如果它在不需要它時運行會更好,而不是在需要時運行不起作用。 – 2012-01-21 18:12:55

+0

我會接受這一點,因爲它明確指出我錯過/忽略了什麼:「'void &&'是一個錯誤」。 – Xeo

10

若干定義取決於declval給出合理結果cv-qualifiedvoid。一個例子是is_assignable

template <class T, class U> 
struct is_assignable; 

處理 作爲未計算的操作數時declval<T>() = declval<U>()是公形成的表達...

意圖是「良好形成」指的是井賦值表達式的形式,而不是declval<T>本身是否格式良好。即我們一次只想擔心一件事。

10

區別在於add_rvalue_reference<>只是真的增加了&&部分,如果T是一個對象或函數類型。如果T不是對象或函數類型(例如void),則不需要添加&&

請參閱this example on Ideone
This webpage of Boost's implementation解釋說:

函數模板declval()的作用是一種T的轉變成一個值,而不使用或評估此功能。這個名字應該引導讀者注意,當且僅當T是左值參考,否則是右值,表達式declval<T>()是左值。爲了擴展這個函數的定義域,我們可以做的更好,通過改變它的聲明有點

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

這保證了我們也可以利用CV void爲模板參數。

相關問題