Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable implicit constructor conversion, while allowing copy-initialization

Tags:

c++

c++11

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

like image 436
jyavenard Avatar asked May 04 '15 05:05

jyavenard


People also ask

What is a default and conversion constructor in Java?

Answered on 23-12-2021. A conversion constructor is a single-parameter constructor that is declared without the function specifier explicit . The compiler uses conversion constructors to convert objects from the type of the first parameter to the type of the conversion constructor's class. 0.

What is an implicitly declared constructor?

implicit constructor is a term commonly used to talk about two different concepts in the language, the. implicitly declared constructor which is a default or copy constructor that will be declared for all user classes if no user defined constructor is provided (default) or no copy constructor is provided (copy).

What is a default and conversion constructor?

In C++, if a class has a constructor which can be called with a single argument, then this constructor becomes conversion constructor because such a constructor allows automatic conversion to the class being constructed. Example.

What are copy constructors in C++?

Copy Constructor in C++ A copy constructor is a member function that initializes an object using another object of the same class. In simple terms, a constructor which creates an object by initializing it with an object of the same class, which has been created previously is known as a copy constructor.


1 Answers

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.

like image 110
M.M Avatar answered Nov 04 '22 21:11

M.M