§20.2.4 [declval]
template <class T>
typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand
Run Code Online (Sandbox Code Playgroud)
为何add_rvalue_reference在这里使用?
从§20.9.7.2 [meta.trans.ref]上add_rvalue_reference:
如果
T命名对象或函数类型,则成员typedeftype应命名T&&; 否则,type应说出名称T.[ 注意:此规则反映了引用折叠的语义(8.3.2).例如,当类型T命名类型时T1&,类型add_rvalue_reference<T>::type不是右值引用.- 尾注 ]
因为add_rvalue_reference无论如何都要反映参考折叠,为什么不使用T&&如下?
template<class T>
T&& declval();
Run Code Online (Sandbox Code Playgroud)
怎么可能出错?两个版本之间到底有什么区别?
Pub*_*bby 17
我不知道这是否是实际原因,但却add_rvalue_reference有不同的行为void.
add_rvalue_reference<void>::type很简单void.
void&& 是一个错误.
How*_*ant 11
几个定义取决于declval为cv-qualified 提供合理的结果void.一个例子是is_assignable:
template <class T, class U>
struct is_assignable;
Run Code Online (Sandbox Code Playgroud)
declval<T>() = declval<U>()当被视为未评估的操作数时,表达式是良好的...
意图是"格式良好"指的是赋值表达式的良好形成,而不是declval<T>它本身是否格式良好.也就是说,我们一次只想担心一件事.
小智 11
不同之处在于,如果是对象或函数类型,add_rvalue_reference<>则只添加&&部分T.如果T不是对象或函数类型(例如void),则不想添加&&.
在Ideone上查看此示例.
Boost实施的这个网页解释说:
函数模板的作用是在不使用或评估此函数的情况
declval()下将类型T转换为值.该名称应该引导读者注意这样一个事实:declval<T>()当且仅当T是左值引用时,表达式是左值,否则是右值.要扩展此函数的域,我们可以通过将其声明更改为更好Run Code Online (Sandbox Code Playgroud)template<class T> typename std::add_rvalue_reference<T>::type declval(); // not used这确保我们也可以使用cv
void作为模板参数.