【问题标题】:Why does std::declval add a reference?为什么 std::declval 添加引用?
【发布时间】:2014-10-31 16:19:17
【问题描述】:

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

【问题讨论】:

  • T 是否需要可复制才能使T 成为有效的返回类型? T &amp;&amp; 会避免这种情况。
  • 我认为是为了支持不能按值返回的类型,例如函数类型、数组类型和抽象类。
  • @user2357112:可移动性就足够了。
  • @Mehrdad 任何类类型都可以是返回类型,可移动性是不必要的。
  • @Potatoswatter:我从没说过可移动性是必要的。

标签: c++ c++11 decltype


【解决方案1】:

仅当函数调用本身是 decltype 的操作数或作为 @ 的操作数的逗号运算符的右操作数时,“没有为在 decltype 中返回对象类型的纯右值的函数引入临时函数”规则适用987654324@(§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 会阻止 declval 在不完整类型、带有私有析构函数的类型等方面的大多数重要用途:

class D;

int f(D &&);

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

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

【讨论】:

  • 啊,我没有意识到 unchecked 析构函数是一个特殊的异常。我的例子完全被误导了。
  • "没有为在decltype中返回对象类型的prvalue的函数引入临时" 变成 "如果表达式是prvalue不是(可能带括号的)立即调用(C++20 起),临时对象不会从该纯右值具体化。” c++17 起en.cppreference.com/w/cpp/language/decltype
【解决方案2】:

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

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

【讨论】:

  • 这不是真的,T 不必是可复制或可移动的,它甚至可以是不完整的,见coliru.stacked-crooked.com/a/3f387e9e4e0ce190
  • @Jamboree:使用typedef int A[4] 将使A f(); 无效代码。
  • 我看不出这和declval有什么关系。
  • @jrok:当T 是一个数组时,不能使用基于按值返回T 的函数的declval 定义。
  • 我知道。但我不知道你为什么要对数组类型使用 declval(可能只是我缺乏想象力)。
【解决方案3】:

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

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

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

【讨论】:

  • 1.我不建议使用T{}。 2.decltype返回一个右值或左值引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-15
相关资源
最近更新 更多