Disallow copy constructor, but allow implicit copy from another type

Here is my code, I disabled the copy constructor, but it also disables my implicit copy from other types. Any work in this case?

Tested on: 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&)’
}

      

+3


source to share


2 answers


Either give test

a move constructor:

test(test&&) = default;

      

or use direct initialization:

test a{item{10}};

      

There is no other workaround. Copy-initialization, where the destination type is the class type, for example test a = item{10};

, always requires a callable copy or move instance.




The corresponding rule is specified in Β§8.5 [dcl.init] / p17:

If the target type is a class class (possibly cv-qualit):

  • If initialization is direct initialization, or if it is copy-initialization, where the cv-unqualified version of the source type is the same class as the derived class of the destination class, the constructors. The corresponding constructors are listed (13.3.1.3), and the best one is chosen by overloading resolution (13.3). The so-chosen constructor is called to initialize the object with an initializer expression or list of expressions as its argument (s). If no constructor is applied or the overload resolution is ambiguous, the initialization is poorly formed.
  • Otherwise (that is, for the rest of the copy initialization cases) custom conversion sequences that can convert from source type to destination type or (when a conversion function is used) to its derived class are listed as described in 13.3.1.4, and the best one is selected using overload permissions (13.3). If the conversion cannot be performed or is ambiguous, the initialization is poorly formed. The selected function is called with the initializer expression as an argument; if the function is a constructor, the call initializes a temporary version of the cv-unqualified version of the target type. The temporary is prvalue. The result of the call (which is temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object,which is the destination of the copy initialization. In some cases, implementations are allowed to eliminate the inherent copying of direct initialization by directly constructing an intermediate result into an initialized object; see 12.2, 12.8.

Source item

type, destination type test

, it copies the initialization, so it falls under the second marker point. There is only one conversion available using the constructor test(const item& a)

, so a temporary type value is test

built from item

and then used to directly initialize the destination according to the first token point. This, in turn, must call a constructor test

, which can take an argument const test &

or test &&

. Even if the copy or move is rejected, you should still have a constructor like this.

+5


source


There are three options I can think of:

1) Move constructor
2) Assignment operator + default constructor
3) Call constructor explicitly



#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};
}

      

0


source







All Articles