为什么std :: declval添加引用?
std::declval
是一个编译时间实用程序,用于构buildexpression式以确定其types。 它是这样定义的:
template< class T > typename std::add_rvalue_reference<T>::type declval() noexcept;
这不是更简单吗?
template< class T > T declval() noexcept;
引用返回types的优点是什么? 不应该叫做declref
?
我发现的最早的历史例子是n2958 ,它调用函数的value()
但总是返回一个引用。
注意, decltype
的操作数不需要有一个可访问的析构函数,也就是说,它不是在语义上被检查为一个完整的expression式。
template< typename t > t declprval() noexcept; class c { ~ c (); }; decltype ( declprval< c >() ) * p = nullptr; // OK
只有在函数调用本身是decltype
的操作数,或者作为decltype
的操作数的逗号运算符的右操作数时,“适用于在decltype
返回对象types的函数的临时函数”(§5.2.2[expr .call] / p11),这意味着给定的OP中的declprval
,
template< typename t > t declprval() noexcept; class c { ~ c (); }; int f(c &&); decltype(f(declprval<c>())) i; // error: inaccessible destructor
不编译。 更一般地说,返回T
将阻止大多数不完整types的非重要用法,带有私有析构函数的types等等:
class D; int f(D &&); decltype(f(declprval<D>())) i2; // doesn't compile. D must be a complete type
这样做几乎没有什么好处,因为xvalues与prvalues几乎没有什么区别,除非使用decltype
,并且通常不会直接在declval
的返回值上使用decltype
– 您已经知道types。
数组不能返回值,因此即使只是声明一个函数返回一个数组是无效的代码。
但是,您可以通过引用返回一个数组。
decltype()
的目的是要有一个expression式作为T
的有效值,把它作为expressionT
的expression式。 问题是,在C ++中,typesT
可以是不可复制的,甚至是非默认可构造的。 所以使用T{}
来达到这个目的是行不通的。
decltype()
所做的是将一个右值引用返回给T
右值引用对于任何typesT
都应该是有效的,所以它保证我们有一个来自T
的右值引用的有效的T
,并且保证我们可以有任何typesT
的右值引用。 这就是诀窍。
考虑decltype()
为“ 给我一个T
型的有效expression式 ”。 当然它的用途是用于重载分辨率,types确定等。 因为它的目的是返回一个有效的expression式 (在语法上),而不是返回一个值。 这反映在std::declval()
没有被定义的事实,它唯一的声明。
如果定义了,我们又有了最初的问题(我们必须为任意typesT
构造一个值,而这是不可能的)。