§20.2.4 [declval]
template <class T>
typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand
为什么要在这里使用add_rvalue_reference
?
来自add_rvalue_reference
上的§20.9.7.2 [meta.trans.ref]
如果T
命名对象或函数类型,则成员
type
应命名为T&&
;否则,type
应命名为T
。注意:此规则反映了引用折叠(8.3.2)的语义。例如,当类型T
将类型命名为T1&
时,类型add_rvalue_reference<T>::type
不是右值引用。-end笔记
既然add_rvalue_reference
旨在以任何方式反映引用折叠,为什么不像下面这样使用T&&
呢?
template<class T>
T&& declval();
会出什么问题呢?这两个版本到底有什么不同?
发布于 2012-01-22 01:48:08
我不知道这是否是真正的原因,但是add_rvalue_reference
对void
有不同的行为。
add_rvalue_reference<void>::type
就是简单的void
。
void&&
是一个错误。
发布于 2012-01-22 01:53:19
有几个定义依赖于declval
为cv合格的void
提供合理的结果。is_assignable
就是一个例子
template <class T, class U>
struct is_assignable;
当将表达式declval<T>() = declval<U>()
视为未计算的操作数时,该表达式的格式是正确的...
其意图是“良构的”指的是赋值表达式的良构,而不是declval<T>
本身是否良构。也就是说,我们一次只需要担心一件事。
发布于 2012-01-22 01:54:44
不同之处在于,只有当T
是对象类型或函数类型时,add_rvalue_reference<>
才真正添加&&
部件。如果T
不是对象或函数类型(例如void
),您就不想添加&&
。
This webpage of Boost's implementation解释说:
函数模板
declval()
的作用是在不使用或计算此函数的情况下将类型T
转换为值。这个名字应该引导读者注意这样一个事实:当且仅当T
是左值引用时,表达式declval<T>()
才是左值,否则是右值。为了扩展这个函数的域,我们可以做得更好一些,将它的声明改为
模板类型名称std::add_rvalue_reference::type declval();//不使用
这确保了我们还可以使用cv void
作为模板参数。
https://stackoverflow.com/questions/8955052
复制相似问题