C++ 为什么std::declval添加引用?

C++ 为什么std::declval添加引用?,c++,c++11,decltype,C++,C++11,Decltype,是一个编译时实用程序,用于构造表达式以确定其类型。定义如下: template< class T > typename std::add_rvalue_reference<T>::type declval() noexcept; 数组不能按值返回,因此即使函数声明按值返回数组也是无效代码 但是,您可以通过引用返回数组。decltype()的目的是让表达式充当类型为T的有效值,将其作为T的表达式中的T。问题是C++中的一个类型 t>代码>不能是可复制的,甚至是非默认可构造

是一个编译时实用程序,用于构造表达式以确定其类型。定义如下:

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

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


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

decltype()的目的是让表达式充当类型为
T
的有效值,将其作为
T
的表达式中的
T
。问题是C++中的一个类型<代码> t>代码>不能是可复制的,甚至是非默认可构造的。因此,使用
T{}
来达到这个目的是行不通的

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

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

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

template< typename t >
t declprval() noexcept;

class c { ~ c (); };

int f(c &&);

decltype(f(declprval<c>())) i;  // error: inaccessible destructor

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

要使
t
成为一个有效的返回类型,难道
t
不需要可复制吗
T&&
可以避免这种情况。我认为这是为了支持不能按值返回的类型,例如函数类型、数组类型和抽象类。@user2357112:可移动性就足够了。@Mehrdad任何类类型都可以是返回类型,可移动性是不必要的。@Potatostater:我从来没有说过可移动性是必要的。那不是真的,T不必是可复制或可移动的,它甚至可以是不完整的,请参见@Jamboree:using
typedef int A[4]
将使
A f()无效代码。我看不出这与
declval
@jrok有什么关系:当
t
是数组时,不能使用基于返回
t
值的函数的
declval
定义。我知道。但我不知道你为什么要将declval与数组类型一起使用(可能是我缺乏想象力)。啊,我没有意识到未经检查的析构函数是一个特殊的例外。我的例子完全被误导了。“没有为decltype中返回对象类型的prvalue的函数引入临时变量”变成“如果表达式是一个prvalue而不是一个(可能是括号中的)立即调用(从C++20开始),则临时对象不会从该prvalue具体化。”从C++17开始。1.我没有提议使用
t{}
。2.
decltype
返回右值或左值引用。
template< typename t >
t declprval() noexcept;

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

class c { ~ c (); };

int f(c &&);

decltype(f(declprval<c>())) i;  // error: inaccessible destructor
class D;

int f(D &&);

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