为什么'declval'根据'add_rvalue_reference<T>::type'而不是"T&&"来指定?

Why is 'declval' specified in terms of 'add_rvalue_reference<T>::type' and not 'T&&'?

本文关键字:declval type reference rvalue lt 为什么 根据 gt add      更新时间:2023-10-16

§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不是右值引用。--结束注释]

既然add_rvalue_reference无论如何都是用来反映引用崩溃的,为什么不像下面这样使用T&&呢?

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

可能出了什么问题?这两个版本到底有什么不同?

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

CCD_ 17简称为CCD_。

void&&是一个错误。

几个定义取决于declval,为cv合格void给出合理的结果。一个例子是is_assignable:

template <class T, class U>
struct is_assignable;

表达declval<T>() = declval<U>()在处理时形成良好作为未求值的操作数。。。

其意图是,"良好形式"指的是赋值表达式的良好形式,而不是declval<T>本身是否良好形式。也就是说,我们一次只想担心一件事。

区别在于add_rvalue_reference<>只有在T是对象或函数类型的情况下才真正添加&&部分。如果T不是对象或函数类型(例如void),则不希望添加&&

请参阅Ideone上的此示例
Boost实现的这个网页解释道:

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

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

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