有人可以向我解释为什么以下内容无法编译吗?我不确定为什么编译器会认为我正在调用副本构造函数。
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;
};
但这在您的情况下不起作用,默认规则的默认构造函数被删除,因为规则继续