【问题标题】:2 questions about cppreference.com's explanation of decltype关于cppreference.com对decltype的解释的2个问题
【发布时间】:2021-11-11 16:25:02
【问题描述】:

当我阅读this online c++ reference page about decltype

我想知道这一段:

如果表达式是一个返回类纯右值的函数调用 type or 是一个逗号表达式,其右操作数是这样的函数调用,不会为该prvalue引入临时对象。 (直到 C++17)

我的问题是:引入或不引入临时性,重要吗?

还有这一段:

请注意,如果对象的名称带有括号,则将其视为 作为一个普通的左值表达式,因此 decltype(x) 和 decltype((x)) 通常是不同的类型。

又是我的问题:区别对待它们的理由是什么?

有谁能帮我看看我所处的黑暗角落吗?谢谢。

【问题讨论】:

标签: c++ decltype temporary


【解决方案1】:

引入或不引入临时性,重要吗?

如果您查看使用函数结果的表达式,这会更有意义:

// given
template<typename T> struct Foo {};
template<typename T> Foo<T> foo();
template<typename T> void bar(const Foo<T>&);

// This:
bar(foo<int>());

// Is equivalent to: 
{
  Foo<int>&& tmp = foo<int>();
  bar(tmp);
}

// So should tmp "exist" here?
using T = decltype(foo<int>());

您很容易争辩说foo&lt;int&gt;() 表达式实际上等价于Foo&lt;int&gt;&amp;&amp; tmp = foo&lt;int&gt;()。如果tmp 的存在在某种decltype() 上下文中是不可取的,那么需要明确说明。

tmp 在这里绝对是不可取的。它会导致创建 Foo&lt;int&gt; 特化。但仅仅因为你已经确定了一个类型并不意味着你实际上正在使用它。类型别名也是如此。

演示:(参见godbolt

#include <type_traits>

template<typename T>
struct Foo {
    // Will cause a compile error if it's ever instantiated with int
    static_assert(!std::is_same_v<T, int>);
};

using FooInt = Foo<int>;

template<typename T>
Foo<T> foo() {
    return {};
}

void bar() {
  // Does not cause Foo<int> to exist just yet
  using T = decltype(foo<int>());

  // This instantiates Foo<int> and causes the compile error
  // T x;
}

区别对待它们的理由是什么?

注意以下内容更多地是关于如何推理的指南。实际的技术细节有所不同,但可能会相当复杂。

不要认为括号有什么特别之处。相反,将其视为decltype(id-expression) 是一种特殊情况。

假设我们有以下声明:int x;

x 表达式的行为不像 int,而是 int&amp;。否则x = 3; 没有意义。

尽管如此,decltype(x) 仍然是 int。这是特例:decltype(id-expression) 返回标识符本身的类型,而不是表达式的类型。

另一方面,(x) 的行为也类似于 int&amp;,但由于它不是 id-expression,因此它被解释为任何正则表达式。所以decltype((x))int&amp;

#include <type_traits>

int x = 0;

using T = decltype(x);
using U = decltype((x));

static_assert(std::is_same_v<T, int>);
static_assert(std::is_same_v<U, int&>);

【讨论】:

  • 非正式地将其视为“x 表达式的类型是int&amp;”有时会有所帮助,但这可能会导致理解其他技术细节时出现问题。从技术上讲,表达式永远没有引用类型。更准确地说,每个表达式都有一个类型和一个值类别,而普通的decltype在值类别中组合有时会得到引用类型。 (x)int 类型的左值,所以decltype((x))int&amp;decltype(id-expression) 特例使用匹配声明符的类型,而不是表达式的类型和类别。
  • @aschepler 谢谢。为了避免误导人们,我稍微改进了措辞,但保留了简化的观点,以使答案尽可能对初学者友好。
  • 内容丰富且乐于助人。谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-07
  • 1970-01-01
  • 2011-05-16
相关资源
最近更新 更多