尽管删除了复制构造函数,但 C++14 函数返回对象数组

Tob*_*fer 2 c++ c++14 decltype-auto

从旧的 C++98 我知道,如果函数声明/定义中没有提到,则返回类型复制(按值),否则使用地址运算符“&”。

现在我正在使用 auto 和 decltype 的概念来让编译器确定返回类型。在一个例子中,我写了一个class A 除了默认的 ctor 之外的任何其他 ctors 都被删除的地方(A 类取自一个真实的项目 - 我调查了一些问题)。类 A 的对象与 etl::array(嵌入式模板库,在堆栈上以固定大小创建的数组)一起构造,请参见下面的示例代码。

#include <etl/array.h>
#include <iostream>

class A {
public:
    A(std::uint8_t val) : _val(val){}
    A(A const&) = delete;      // copy delete
    A& operator=(A&) = delete; // copy assign delete
    A(A&&) = default;          // move default
    A& operator=(A&&) = delete;// move assign delete
    ~A() = default;
    void whoAmI(){std::cout << " I am A! " << std::endl;}
private:
    std::uint8_t _val;
};

decltype(auto) X(std::uint8_t val) {
  return etl::array<A,1>{A{val}};
}

int main()
{
    decltype(auto) x = X(5U);
    for (auto& it : x) {
      it.whoAmI();
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望,etl::array 将被复制到 main() 例程中并分配给局部变量 x。由于已删除的复制构造函数,我不希望数组中有 A 的副本。但是,代码可以编译,我可以在 etl::array 的元素上调用该函数。我不明白为什么这会起作用以及为什么它正在编译?我想知道decltype(auto)最后是什么类型。我之所以选择decltype(auto)是因为 Scott-Meyers 第 2 项和第 3 项。对于第 3 项,我不确定对 decltype 主题有完整的了解。

当我逐步执行代码时,它工作正常,让我落后了..

非常感谢有关此主题的任何帮助!


非常感谢您的帮助,这对我很有启发。现在我终于知道它为什么起作用了:-D - 你让我开心了!

cig*_*ien 5

decltype(auto)用于确定表达式的类型和值类别。当用作返回类型时,它让函数根据 return 语句中的表达式决定返回值类型应该是什么。在这个例子中,因为你在返回的表达式中使用了一个临时的,它会推导出一个右值。

在本声明中:

decltype(auto) x = X(5U);
Run Code Online (Sandbox Code Playgroud)

语法是复制初始化,它具有x从表达式初始化变量的效果X(5U)。您有一个默认的移动构造函数,编译器使用此构造函数x从X.

请注意,从 C++17 开始,由于强制复制省略,您甚至可以删除移动构造函数,并且代码仍然有效,因为不需要构造函数来初始化x.