禁止复制构造函数,但允许其他类型的隐式复制

w00*_*00d 3 c++ class copy-constructor c++11

这是我的代码,我禁用了复制构造函数,但它也禁用了其他类型的隐式副本.在这种情况下的任何解决方法?

测试: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&)’
}
Run Code Online (Sandbox Code Playgroud)

T.C*_*.C. 5

test动作构造函数:

test(test&&) = default;
Run Code Online (Sandbox Code Playgroud)

或使用直接初始化:

test a{item{10}};
Run Code Online (Sandbox Code Playgroud)

没有其他解决方法.复制初始化,其中目标类型是类类型,例如test a = item{10};,始终需要可调用副本或移动构造函数.


相关规则在§8.5[dcl.init]/p17中规定:

如果目标类型是(可能是cv限定的)类类型:

  • 如果初始化是直接初始化,或者它是复制初始化,其中源类型的cv-nonqualified版本与目标类相同的类或派生类,则考虑构造函数.列举了适用的构造函数(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从该构造的prvalue临时类型item然后用于根据第一个项目符号点直接初始化目标.反过来,这必须调用一个test可以接受一个const test &test &&参数的构造函数.即使复制或移动被省略,您仍然必须具有这样的构造函数.