Reputation: 5606
Here is my code, I disable the copy constructor, but it also disables my implicit copy from other types. Any work around 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&)’
}
Upvotes: 3
Views: 326
Reputation: 137404
Either give test
a move constructor:
test(test&&) = default;
or use direct initialization:
test a{item{10}};
There's no other workaround. Copy-initialization where destination type is a class type, such as test a = item{10};
, always requires a callable copy or move constructor.
The relevant rule is specified in §8.5 [dcl.init]/p17:
If the destination type is a (possibly cv-qualified) class type:
- If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.
- Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3). If the conversion cannot be done or is ambiguous, the initialization is ill-formed. The function selected is called with the initializer expression as its argument; if the function is a constructor, the call initializes a temporary of the cv-unqualified version of the destination type. The temporary is a prvalue. The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization. In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized; see 12.2, 12.8.
The source type is item
, the destination type is test
, it's copy initialization, so it falls under the second bullet point. There's only one available conversion using the test(const item& a)
constructor, so a prvalue temporary of type test
is constructed from the item
and then used to direct-initialize the destination in accordance with the first bullet point. This, in turn, must call a constructor of test
that can accept a const test &
or test &&
argument. Even if the copy or move is elided, you still must have such a constructor available.
Upvotes: 5
Reputation: 3338
There are three options I can think of:
1) Move constructor
2) Assignment operator + default constructor
3) Calling the 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};
}
Upvotes: 0