有人可以向我解释为什么以下内容无法编译吗?我不确定为什么编译器会认为我正在调用副本构造函数。

struct test {
  const int index;
 private:
  test(const test&) = delete; // comment out this line and voila.
};

int main(int argc, char** argv) {
  test arg{1};
  return arg.index;
}

GCC失败并显示此消息(可在http://www.compileonline.com/compile_cpp11_online.php中重现)
main.cpp: In function ‘int main(int, char**)’:
main.cpp:8:13: error: no matching function for call to ‘test::test(<brace-enclosed initializer list>)’
   test arg{1};
             ^
main.cpp:8:13: note: candidate is:
main.cpp:4:3: note: test::test(const test&) <deleted>
   test(const test&) = delete;
   ^
main.cpp:4:3: note:   no known conversion for argument 1 from ‘int’ to ‘const test&’

最佳答案

您似乎在这里有两个问题。标题询问默认初始化,而您的代码使用列表初始化。

您所依赖的是列表初始化,而不是默认的初始化,尤其是您正在尝试进行聚合初始化。有关规则,请参见8.5.4p3:

在8.5.1中:

那正是您想要的,但是拥有“用户提供的构造函数”将禁用它。这与“用户声明的构造函数”不同,但是某些编译器编写者可能将两者混淆了(请参阅@dyp's answer)。
据我所知,没有办法为非聚合类型显式启用聚合初始化。但是,您可以解决此问题。使您的类型为聚合,并通过另一种方式禁用复制构造:

struct test
{
  const int index;
  struct nocopy { nocopy() = default; nocopy(const nocopy&) = delete; } copy_disabled;
};
这行得通,因为12.8p11说:

但是请注意,您不能仅从boost::noncopyable继承,因为聚合不能具有基类。

处理默认初始化的情况要容易一些。回忆一下具有编译器声明的默认构造函数的条件:
  • 没有用户声明的构造函数。

  • 由于已经声明了构造函数(并将其定义为已删除),因此您还摆脱了默认的默认构造函数。
    此规则来自标准中的12.1p4:

    由于默认初始化依赖于编译器声明的默认构造函数,因此只有当没有用户声明的构造函数时,它才能工作。
    您可以通过将默认构造函数显式声明为default来解决此问题,如下所示:
    struct test
    {
      const int index;
      test(void) = default; // <-- ADD THIS
    private:
      test(const test&) = delete;
    };
    
    但这在您的情况下不起作用,默认规则的默认构造函数被删除,因为规则继续

    07-24 09:37
    查看更多