对带花括号的引用类型变量的 decltype

decltype on the variable of reference type with curly braces

考虑以下 code

#include <type_traits>

int main() {
    const int& p = 42;
    auto v1 = decltype(p){};
    static_assert(std::is_same_v<decltype(v1), int>);
    
    decltype(p) v2{};
    static_assert(std::is_same_v<decltype(v2), const int&>);
    // auto v3 = X(const int&)X {};
}

v1 的类型推断为 int。同时 v2 的类型预计会被推断为 const int&。我认为 v1 的第一步可以视为添加一个类型别名 using T = decltype(p);,然后是 auto v4 = T{};。编译器如何处理这个表达式(decltype(p){}T{})?我知道 {} 部分用于实例化,但是 v1 的结果类型怎么不是引用类型?

还有一个问题:有没有一种方法可以使用明确指出的类型 const int&(而不是 decltype(p))来声明与 v1 相同类型的 v3 变量?

任何指向标准的链接将不胜感激。

(致反对者:如果你反对是因为你认为引用 Scott Meyers 不等同于引用标准,哦好吧......)

正如您可以从 Effective Modern C++ 中读到的那样(增加了 errata 的部分,您可以通过搜索 Case 2: 在 link,这只会让下面的阅读更简单,但这对问题来说并不重要):

If ParamType is a non-reference [...] if expr's type is a reference, ignore the reference part. If [...] expr is const, ingore that too. If it's volatile, also ignore that.

其中 param 是声明说明符,在您的情况下只是 auto,即非引用。

换句话说,您是通过普通 auto(而不是 auto&)创建 v1,即通过复制,因此无论您是否使用实体是不是参考,甚至是 const 或不是(或者 volatile 与否,fwiw),因为你正在复制它。

想想更简单的情况,

int i = 3;
int& p = i;
auto v1 = p;

v1而言,它是用一个(i)还是另一个(p)名称初始化真的不重要,相同 实体是已知的,因为它将获得该实体具有的任何值的副本。

auto 类型推导就像模板类型推导一样工作(除了它们处理花括号初始化器的方式不同,这在这种情况下不相关),对于它们两者你可以参考 Scott Meyers 的 Effective Modern C++.

auto v4 = T{};. How this expression (decltype(p){} or T{}) is treated by compiler? I know that {} part is for instantiation, but how the result type is not a reference type?

结果decltype(p){}一个引用类型。 auto 的用法删除了 const 和引用限定符。类型推导解释here,与模板类型推导相同。您可以使用 decltype(auto) 来保留这些限定符(或者,在这种特殊情况下,您可以使用 const auto&)。