关于cppreference.com对decltype解释的2个问题

2 questions about cppreference.com's explanation of decltype

我读书的时候this online c++ reference page about decltype

我想知道这一段:

If expression is a function call which returns a prvalue of class type or is a comma expression whose right operand is such a function call, a temporary object is not introduced for that prvalue. (until C++17)

我的问题是:引入或不引入临时有关系吗?

这一段:

Note that if the name of an object is parenthesized, it is treated as an ordinary lvalue expression, thus decltype(x) and decltype((x)) are often different types.

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

有没有人能帮我一把,让我在黑暗的角落里看到一些光。谢谢。

Introducing or not introducing a temporary, does that matter?

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

// 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<int>() 表达式实际上 等价于 Foo<int>&& tmp = foo<int>()。如果 tmp 的存在在 decltype() 上下文中是不受欢迎的,那么它需要被弄清楚。

tmp在这里绝对是不可取的。它会导致创建 Foo<int> 专业化。但是仅仅因为您识别了一种类型并不意味着您实际上正在使用它。类型别名也是如此。

演示:(参见 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;
}

What's the rationale behind treating them differently?

N.B. 以下更多是关于如何对此进行推理的指南。实际的技术细节是不同的,但它可能会变得相当复杂。

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

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

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

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

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

#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&>);