为什么std::declval添加引用

Why does std::declval add a reference?

本文关键字:引用 添加 declval 为什么 std      更新时间:2023-10-16

std::declval是一个编译时实用程序,用于构造表达式以确定其类型。它是这样定义的:

template< class T >
typename std::add_rvalue_reference<T>::type declval() noexcept;

这不是更简单吗?

template< class T >
T declval() noexcept;

引用返回类型的优点是什么?它不应该被称为declref吗?

我发现的最早的历史例子是n2958,它调用函数value(),但已经总是返回一个引用。

注意,decltype的操作数不需要有可访问的析构函数,即它在语义上不作为完整表达式进行检查。

template< typename t >
t declprval() noexcept;
class c { ~ c (); };
decltype ( declprval< c >() ) * p = nullptr; // OK

只有当函数调用本身是decltype的操作数或是作为decltype的操作数的逗号运算符的右操作数时(§5.2.2[expr.call]/p11),"在decltype中返回对象类型的prvalue的函数不引入临时"规则才适用,这意味着在OP中给定declprval

template< typename t >
t declprval() noexcept;
class c { ~ c (); };
int f(c &&);
decltype(f(declprval<c>())) i;  // error: inaccessible destructor

不编译。更一般地说,返回T将阻止使用不完整类型的declval、具有私有析构函数的类型等进行大多数非平凡的使用:

class D;
int f(D &&);
decltype(f(declprval<D>())) i2;  // doesn't compile. D must be a complete type

这样做几乎没有什么好处,因为xvalues与prvalues几乎没有区别,除非你在它们上使用decltype,而且你通常不会直接在declval的返回值上使用decltype——你已经知道类型了。

数组不能按值返回,因此即使只是按值返回数组的函数声明也是无效代码。

但是,您可以通过引用返回数组。

decltype()的目的是让一个表达式充当T类型的有效值,并将其作为T s的表达式中的T。问题是,在C++中,T类型可能是不可复制的,甚至是不可默认构造的。因此,将T{}用于此目的是行不通的。

decltype()所做的是返回对T的右值引用。右值引用应该对任何类型的T有效,因此它保证我们从T的右值引用中获得有效的T,并且它保证我们可以对任何类型T具有右值引用。这就是诀窍。

decltype()想象为"给我一个类型为T的有效表达式"。当然,它的用途是用于过载解析、类型确定等;因为它的目的是返回有效表达式(在语法意义上),而不是返回值。这反映在std::declval()根本没有定义,它只是声明的
如果定义了它,我们又遇到了最初的问题(我们必须为任意类型的T构造一个值,这是不可能的)。