为什么'declval'用'add_rvalue_reference <t> :: type'而不是'T&amp;&amp;'来指定?</t>

时间:2012-01-21 17:30:54

标签: c++ c++11

§20.2.4 [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不是右值引用。 -end note ]

由于add_rvalue_reference无论如何都要反映引用崩溃,为什么不像以下那样使用T&&

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

可能出现什么问题?两个版本之间到底有什么区别?

3 个答案:

答案 0 :(得分:15)

我不知道这是否是实际原因,但add_rvalue_referencevoid的行为有所不同。

add_rvalue_reference<void>::type只是void

void&&是一个错误。

答案 1 :(得分:10)

若干定义取决于declval cv-qualified void提供合理的结果。一个例子是is_assignable

template <class T, class U>
struct is_assignable;
  

表达式declval<T>() = declval<U>()在处理时格式正确   作为一个未经评估的操作数......

意图是“格式良好”是指赋值表达式的良好形成,而不是declval<T>本身是否格式良好。即我们一次只想担心一件事。

答案 2 :(得分:10)

不同之处在于,如果add_rvalue_reference<>是对象或函数类型,&&只会真正添加T部分。如果T不是对象或函数类型(例如void),则您不想添加&&

请参阅this example on Ideone This webpage of Boost's implementation解释说:

  

函数模板declval()的作用是将类型T转换为值,而不使用或评估此函数。当且仅当declval<T>()是左值引用时,该名称应引导读者注意表达式T是左值的事实,否则为右值。要扩展此函数的域,我们可以通过将其声明更改为

来做得更好
template<class T>
typename std::add_rvalue_reference<T>::type declval(); // not used
     

确保我们也可以使用cv void作为模板参数。