在匿名类中返回 *this 时,“自动”返回类型的类型是什么?

Kat*_*ate 35 c++ class auto c++11

在这段代码中:

struct
{
    auto operator[](const char*)
    {
        return *this;
    }

} m_some_class;
Run Code Online (Sandbox Code Playgroud)

这里的类型是什么auto

Ted*_*gmo 32

这里的类型是什么auto

类型为decltype(m_some_class)- 即,返回值与变量的类型相同m_some_class


请注意,函数会返回一个副本*this

如果需要对 的引用,*this则可以使用 , auto&或者,从 C++14 开始,使用更通用的decltype(auto).

  • @Ruslan:如果我记得的话,“nullptr”是一个_关键字_,而不是一个标识符(否则你必须在标头中使用它)。`nullptr_t` 是 `<cstddef>` 中定义的 `decltype(nullptr)` 的 typedef https://en.cppreference.com/w/cpp/language/nullptr (6认同)
  • @MooingDuck 没有命名类型,真的吗?`static_assert(std::is_same_v<std::nullptr_t,decltype(nullptr)>);` 编译得很好,所以 `std::nullptr_t` 是 `nullptr` 的命名类型。 (2认同)

nay*_*yab 18

对于匿名结构类型,编译器在内部创建一个名称,并且在您的情况下 auto 返回结构。

您可以在下面看到,您的匿名结构被命名__anon_1_1并且该operator[]函数返回__anon_1_1结构对象。m_some_class是类型的实例__anon_1_1

cppinsights网站提供了一种理解方式

你的代码

struct
{
    auto operator[](const char*)
    {
        return *this;
    }

}m_some_class;
Run Code Online (Sandbox Code Playgroud)

编译器版本

struct __anon_1_1
{
  inline __anon_1_1 operator[](const char *)
  {
    return __anon_1_1(*this);
  }
  
  // inline constexpr __anon_1_1() noexcept = default;
  // inline constexpr __anon_1_1(const __anon_1_1 &) noexcept = default;
};

__anon_1_1 m_some_class = __anon_1_1();
Run Code Online (Sandbox Code Playgroud)

  • 目前还不清楚这实际上是内部使用的名称,而不是诊断的产物(必须生成一些名称以避免错误消息中出现空格)。在实践中,没有什么理由不这样做,但这就是为什么我们不做出假设,而只是按照标准进行编码(即认为该类型没有名称)。 (4认同)

Roh*_*ari 10

给定代码中的行:

return *this;
Run Code Online (Sandbox Code Playgroud)

返回结构m_some_class本身,即的类型operator[]是:

decltype(m_some_class); // i.e. the type returned is the same as the struct
Run Code Online (Sandbox Code Playgroud)

另外,请注意,这只会返回结构的副本实例,因为传递的参数没有被赋予任何引用操作符。对结构副本所做的任何更改都不会影响原始结构。


什么是auto关键字?

auto关键字通常用于程序员不知道某些内容的类型或键入时间太长的情况。

此外,由 定义的类型auto可能因各种情况而异。例如:

auto len = vector.size(); // len is now defined as size_t in compile time
Run Code Online (Sandbox Code Playgroud)

在某些系统中,len可能unsigned long和在我的情况下的类型是,在unsigned long long这里您无法明确定义在这个不确定的地方正确使用哪个限定符。这里我们使用auto关键字。


dfr*_*fri 8

以下所有标准参考均指N4659:2017 年 3 月后 Kona 工作草案/C++17 DIS


TLDR:占位符返回类型推导

类是匿名的并不重要,因为返回类型仅从return语句中推导出来。

// Denote the type of the anonymous class as 'T'.

// Return type deduced to 'T'
auto operator[](const char*)
{
    return *this;
}

// Return type deduced to 'T&'
auto& operator[](const char*)
{
    return *this;
}

// Return type deduced to 'T&'
decltype(auto) operator[](const char*)
{
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

详细信息和相关标准段落如下。


占位符返回类型推导:auto(C++11 及以后)

来自[expr.unary.op]/1 [提取,强调我的]:

[expr.unary.op]/1一元运算*符执行间接操作:应用它的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是引用对象或函数的左值表达式所指向的。[...]

因此,结果*this是一个左值,指向调用操作符调用的对象。

来自[dcl.spec.auto]/1[dcl.spec.auto]/2 [提取,强调我的]:

[dcl.spec.auto] / 1autodecltype(auto) 类型说明符用于指示该占位符类型将在后面通过扣除从一个初始值设定取代。[...]

[dcl.spec.auto]/2占位符类型可以与函数声明符 [...] 一起出现在此类声明符有效的任何上下文中。[...]如果函数声明的返回类型包含占位符类型,则函数的返回类型是从非丢弃return语句中推导出来的[...]。

来自[dcl.type.auto.deduct]/2[dcl.type.auto.deduct]/4 [提取,强调我的]:

[dcl.type.auto.deduct] / 2 A型T包含占位符类型,和对应的初始值设定e,被确定如下:

  • (2.1) 对于return在声明为返回类型且包含占位符类型的函数中出现的非丢弃语句, T是声明的返回类型并且e是返回语句的操作数。如果 return 语句没有操作数,则evoid();
  • [...]

[dcl.spec.auto]/4如果占位符是自动类型说明符,则使用模板参数推导规则确定推导的类型T'替换T [...]

[?例子:

const auto &i = expr;
Run Code Online (Sandbox Code Playgroud)

的类型i是以下发明的函数模板u的调用 f(expr)中参数的推导类型:

template <class U> void f(const U& u);
Run Code Online (Sandbox Code Playgroud)

?—?结束示例?]

因此,成员运算符函数的返回类型

auto operator[](const char*)
{
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

匿名类型的类型,例如,T是以下发明的函数模板u调用f(*this)中参数的推导类型:

template <class U> void f(U u);
Run Code Online (Sandbox Code Playgroud)

其中,如上所述,*this是一个左值,因此返回类型推导出为T;即匿名类的类型。

使用相同的参数,返回成员运算符函数

auto& operator[](const char*)
{
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

匿名类型,例如T,是T&

根据上面的论点,类是匿名的并不重要,因为返回类型仅从return语句中推导出来。


占位符返回类型推导:decltype(auto)(C++14 及以后)

如果我们要替换占位符返回类型auto与占位类型decltype(auto),不同的规则支配的返回类型是如何确定的。

decltype(auto) operator[](const char*)
{
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

来自[dcl.type.auto.deduct]/5 [提取,强调我的]:

如果占位符是decltype(auto)类型说明符,T则应为单独的占位符。推导出的类型T如 [dcl.type.simple] 中所述确定,就好像e它是 的操作数一样decltype

并且,从[dcl.type.simple]/4[dcl.type.simple]/4.3应用 [extract]:

对于表达式e, 表示的类型decltype(e)定义如下:

  • [...]
  • (4.4) 否则,如果e是左值,decltype(e)则是T&,其中T是 的类型e

如上所述,e(返回语句;*this)是一个左值,并且[dcl.type.simple]/4.1[dcl.type.simple]/4.2[dcl.type.simple]/4.3 都不适用于这里。

因此,使用decltype(auto)占位符类型修改的 OP 示例中的返回类型是T&.