这是我的代码,我禁用了复制构造函数,但它也禁用了其他类型的隐式副本。在这种情况下有什么解决方法吗?
测试:g ++(GCC)4.7.1
struct item {
int b;
};
class test {
public:
test(const test& copy) = delete;
test(const item& a) {
std::cout << "OK " << a.b << std::endl;
}
};
int main() {
test a = item{10}; //error: use of deleted function ‘test::test(const test&)’
}
答案 0 :(得分:5)
给test
一个移动构造函数:
test(test&&) = default;
或使用直接初始化:
test a{item{10}};
没有其他解决方法。目标类型是类类型的复制初始化,例如test a = item{10};
,总是需要可调用的副本或移动构造函数。
相关规则在§8.5[dcl.init] / p17:
中规定如果目标类型是(可能是cv限定的)类类型:
- 如果初始化是直接初始化,或者是复制初始化,那么cv-nonqualified版本的源 type与类的类相同,或者是类的派生类 目的地,建设者被考虑。适用的构造函数 列举(13.3.1.3),并通过过载选择最好的一个 决议(13.3)。如此选择的构造函数被调用以初始化 对象,使用初始化表达式或表达式列表作为其对象 参数(一个或多个)。如果没有构造函数适用,或者重载解析是 暧昧,初始化是不正确的。
- 否则(即,对于剩余的复制初始化情况),可以从源转换的用户定义的转换序列 键入目标类型或(使用转换函数时) 按照13.3.1.4的描述列举其派生类别, 并且通过重载决策(13.3)选择最好的一个。如果 转换不能完成或模糊,初始化是 病态的。使用初始化程序调用所选的函数 表达作为其论点;如果函数是构造函数,则调用 初始化一个临时的cv-nonqualified版本的 目的地类型。临时是一个prvalue。通话的结果 (然后用于构造函数的临时情况) 根据上面的规则,直接初始化对象 复制初始化的目的地。在某些情况下, 允许实现消除此中固有的复制 通过直接构造中间结果直接初始化 进入被初始化的对象;见12.2,12.8。
源类型为item
,目标类型为test
,它是复制初始化,因此它属于第二个项目符号点。使用test(const item& a)
构造函数只有一个可用转换,因此test
构造了item
类型的prvalue临时值,然后根据第一个项目符号点直接初始化目标。反过来,这必须调用test
的构造函数,该构造函数可以接受const test &
或test &&
参数。即使复制或移动被删除,您仍然必须有这样的构造函数。
答案 1 :(得分:0)
我可以想到三个选项:
1)移动构造函数
2)赋值运算符+默认构造函数
3)显式调用构造函数
#include <iostream>
struct item {
int b;
};
struct test {
test(const test& copy) = delete;
test(const item& a) {
std::cout << "OK " << a.b << std::endl;
}
// move:
test(test&& from) {}
// added:
test() {}
test& operator = (const test& src) = default;
};
int main() {
//fine after move constructor:
test a = item{10};
//all fine with original
test b(item{20});
//fine after adding .ctor() and op=
test c; c = item{30};
}