Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么删除复制构造函数时默认初始化会失败?_C++_C++11 - Fatal编程技术网

C++ 为什么删除复制构造函数时默认初始化会失败?

C++ 为什么删除复制构造函数时默认初始化会失败?,c++,c++11,C++,C++11,有人能给我解释一下为什么下面没有编译吗?我不知道为什么编译器认为我在调用复制构造函数 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失败并显示此消息(可在中复制)

有人能给我解释一下为什么下面没有编译吗?我不知道为什么编译器认为我在调用复制构造函数

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失败并显示此消息(可在中复制)

main.cpp:在函数“int main(int,char**)”中:
main.cpp:8:13:错误:调用“test::test()”时没有匹配的函数
测试arg{1};
^
main.cpp:8:13:注:候选人为:
main.cpp:4:3:注:test::test(const test&)
测试(常数测试&)=删除;
^
main.cpp:4:3:注意:参数1从'int'到'const test&'没有已知的转换

不是。错误说明:

no matching function for call to ‘test::test(<brace-enclosed initializer list>)
调用“test::test()时没有匹配的函数
这就是你想要做的

因为G++很好,所以它列出了可能的候选者,包括:

test::test(const test&) <deleted>
test::test(常量测试&)

然后它注意到,不仅删除了这个,
testarg{1}将不起作用,因为无法将
1
转换为
test
对象。

它不起作用。错误说明:

no matching function for call to ‘test::test(<brace-enclosed initializer list>)
调用“test::test()时没有匹配的函数
这就是你想要做的

因为G++很好,所以它列出了可能的候选者,包括:

test::test(const test&) <deleted>
test::test(常量测试&)

然后它注意到,不仅删除了这个,
testarg{1}将不起作用,因为您无法将
1
转换为
test
对象。

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


您依赖的是列表初始化,而不是默认初始化,特别是您正试图获得聚合初始化。第8.5.4p3节给出了相关规则:

T
类型的对象或引用的列表初始化定义如下:

  • 如果
    T
    是聚合,则执行聚合初始化(8.5.1)

  • 否则,如果
    T
    是类类型,则将考虑构造函数。列举了适用的构造函数,并通过重载解析(13.3、13.3.1.7)选择了最佳构造函数。如果转换任何参数都需要缩小转换(见下文),则程序的格式不正确
在8.5.1中:

聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),也没有虚拟函数(10.3)

当聚合由初始值设定项列表初始化时,如8.5.4所述,初始值设定项列表中的元素被视为聚合成员的初始值设定项,下标或成员顺序递增。

这正是您想要的,但是有一个“用户提供的构造函数”会禁用它。这与“用户声明的构造函数”不同,但一些编译器编写者可能混淆了两者(请参阅)

据我所知,对于不是聚合的类型,无法显式启用聚合初始化。但是你可以解决这个问题。将您的类型设置为聚合,并以另一种方式禁用复制构造:

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

隐式声明的复制/移动构造函数是其类的内联公共成员。类X的默认复制/移动构造函数定义为已删除(8.4.3),如果X具有:

  • 类类型为
    M
    (或其数组)的非静态数据成员无法复制/移动,因为应用于
    M
    对应构造函数的重载解析(13.3)会导致歧义或从默认构造函数中删除或无法访问的函数
但是请注意,您不能仅仅从
boost::noncopyable
继承,因为聚合不能有基类


处理默认初始化的情况要简单一些。回想一下编译器声明为默认构造函数的条件:

  • 没有用户声明的构造函数
既然您已经声明了一个构造函数(并将其定义为deleted),那么您也已经摆脱了默认的构造函数

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;
}
该规则来自标准中的12.1p4:

X
的默认构造函数是类
X
的构造函数,无需参数即可调用如果类
X
没有用户声明的构造函数,则没有参数的构造函数将隐式声明为默认构造函数(8.4)。隐式声明的默认构造函数是其类的
内联public
成员。类
X
的默认构造函数定义为删除,如果

由于默认初始化依赖于编译器声明的默认构造函数,因此只有在没有用户声明的构造函数的情况下,它才能工作

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;
}
您可以通过将默认构造函数显式声明为默认构造函数来解决此问题,如下所示:

struct test
{
  const int index;
  test(void) = default; // <-- ADD THIS
private:
  test(const test&) = delete;
};
struct测试
{
常数整数指数;

test(void)=default;//这里似乎有两个问题。标题询问默认初始化,代码使用列表初始化


您依赖的是列表初始化,而不是默认初始化,具体而言,您正在尝试获取聚合初始化。有关规则,请参见8.5.4p3:

T
类型的对象或引用的列表初始化定义如下:

  • 如果
    T
    是聚合,则执行聚合初始化(8.5.1)

  • 否则,如果
    T
    是类类型,则会考虑构造函数。将枚举适用的构造函数,并通过重载解析(13.3,13.3.1.7)选择最佳构造函数。如果转换任何参数需要缩小转换(见下文)