Reputation: 2095
Assuming we have something like:
class U {
...
}
and:
class T {
T(const U&) { ... }
}
Now I can declare a variable like so:
U foo;
then T blah(foo);
or T blah = foo
Personally I prefer the later.
Now, should I change the T copy constructor to:
class T {
explicit T(const U&) { ... }
}
I can only declare a variable like:
T blah(foo);
T blah = foo;
will give me a compilation error about the impossibility to convert U to T.
http://en.cppreference.com/w/cpp/language/explicit explains that behaviour with: "Specifies constructors and (since C++11) conversion operators that don't allow implicit conversions or copy-initialization."
Now, the folks I work for require that all our constructors are made explicit. Being an old fart, I don't like changing my coding style too much and forget about T blah = ... style.
The question as such is this: "Is there a way to make a constructor explicit while allowing copy-initialization syntax?"
There are very good reasons to make a constructor explicit, and most of the time, you do want to make it explicit.
Under those instances, I thought I could do something along the line of:
class T {
template<typename = V>
T(const V&) = delete;
T(const U&) { ... }
}
Which would be a catch-all constructor forbidding all conversion but the one I actually want.
Was wondering if there was some trick I could use.
Thanks
Edit: corrected the typo as pointed by Matt McNabb answer. thanks
Upvotes: 5
Views: 2035
Reputation: 141648
T blah = U();
gives the error because, as you correctly explain, copy-initialization calls for implicit conversion of U
to T
; but you have marked the constructor explicit
. (Note: this is not a copy constructor)
Explicit conversion would look like T blah = T(U());
and this should work with no errors.
T blah(U());
is a function declaration (look up most vexing parse). You probably didn't actually try to use blah
as if it were an object, in your test case, otherwise you would have noticed this problem.
Moving onto your question:
Is there a way to make a constructor explicit while allowing copy-initialization syntax?
There is not, as explained by the exact text you quoted about explicit
:
Specifies constructors [...] that don't allow [...] copy-initialization.
You'll have to switch to direct or braced initialization. IMHO that's a good thing anyway, copy-initialization is cumbersome and only good for avoiding MVPs; but now that we can avoid MVPs using braced initialization, it's no longer necessary at all.
You could use either of the following, which work because in all cases a T
is directly and explicitly initialized by the list element:
T blah{ U() };
T blah = T{ U() }; // redundant copy/move operation, probably elided
Note that T blah = { U() };
cannot be used here because that form of initialization (known as copy-list-initialization) cannot use an explicit constructor.
Upvotes: 3