在匿名 class 中 returning *this 时,'auto' return 类型是什么类型?

What is the type of an 'auto' return type when returning *this in an anonymous class?

在此代码中:

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

} m_some_class;

这里auto的类型是什么?

给定代码中的行:

return *this;

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

decltype(m_some_class); // i.e. the type returned is the same as the struct

另外,请注意这只会 return 结构的副本实例,因为传递的参数没有给出任何引用运算符。对结构副本所做的任何更改都不会影响原始结构。


auto 关键字是什么?

auto 关键字通常用于程序员不知道某物的类型或太长而无法输入的情况。

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

auto len = vector.size(); // len is now defined as size_t in compile time

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

对于匿名结构类型,编译器在内部创建一个名称,在您的情况下自动创建 return 结构。

您可以在下面看到,您的匿名结构被命名为 __anon_1_1 并且 operator[] 函数 return 是 __anon_1_1 结构的对象。 m_some_class__anon_1_1

类型的实例

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

你的代码

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

}m_some_class;

编译器版本

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();

What is type of auto in here ?

类型为 decltype(m_some_class) - 即,return 值与变量 m_some_class.

的类型相同

请注意,该函数将 return copy of *this

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

以下所有标准参考均指N4659: March 2017 post-Kona working draft/C++17 DIS.


TLDR: 占位符return类型推导

class 是匿名的没有意义,因为 return 类型仅从 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;
}

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


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

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

[expr.unary.op]/1 The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. [...]

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

来自[dcl.spec.auto]/1 and [dcl.spec.auto]/2[摘录,强调我的]:

[dcl.spec.auto]/1 The auto and decltype(auto) type-specifiers are used to designate a placeholder type that will be replaced later by deduction from an initializer. [...]

[dcl.spec.auto]/2 The placeholder type can appear with a function declarator [...] in any context where such a declarator is valid. [...] If the declared return type of the function contains a placeholder type, the return type of the function is deduced from non-discarded return statements [...].

来自[dcl.type.auto.deduct]/2 and [dcl.type.auto.deduct]/4[摘录,强调我的]:

[dcl.type.auto.deduct]/2 A type T containing a placeholder type, and a corresponding initializer e, are determined as follows:

  • (2.1) for a non-discarded return statement that occurs in a function declared with a return type that contains a placeholder type, T is the declared return type and e is the operand of the return statement. If the return statement has no operand, then e is void();
  • [...]

[dcl.spec.auto]/4 If the placeholder is the auto type-specifier, the deduced type T' replacing T is determined using the rules for template argument deduction. [...]

[ Example:

const auto &i = expr;

The type of i is the deduced type of the parameter u in the call f(expr) of the following invented function template:

template <class U> void f(const U& u);

 — end example ]

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

auto operator[](const char*)
{
    return *this;
}
匿名类型的

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

template <class U> void f(U u);

其中,按照上述,*this 是一个左值,因此 return 类型被推断为 T;即匿名的类型 class.

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

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

的匿名类型,比如说 T,是 T&

根据上面的论点,class 是匿名的没有意义,因为 return 类型仅从 return 语句推导出来。


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

如果我们将占位符 return 类型 auto 替换为占位符类型 decltype(auto),则不同的规则决定了如何确定 return 类型。

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

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

If the placeholder is the decltype(auto) type-specifier, T shall be the placeholder alone. The type deduced for T is determined as described in [dcl.type.simple], as though e had been the operand of the decltype.

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

For an expression e, the type denoted by decltype(e) is defined as follows:

  • [...]
  • (4.4) otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;

如上所述,e(return 语句;*this)是一个左值,[dcl.type.simple]/4.1, [dcl.type.simple]/4.2 nor [dcl.type.simple]/4.3 均不适用于此处。

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

它是 T,其中 T 是 class 的未命名类型。

即使它没有已知的名称,该类型仍然存在,并且可以通过 autodecltype 等机制“使用”。

不过你可能想要 auto&