Home c++ explicit - practical use

explicit – practical use

Author

Date

Category

Understood how constructors work with the explicit keyword.
What is the practical application?

If we want to “fence off” unwanted (to us) transformations, then:

class A {
public:
  A (int val) {
    cout & lt; & lt; "A (int)" & lt; & lt; endl;
  }
  A (char * val) {
    cout & lt; & lt; "A (char *)" & lt; & lt; endl;
  }
};
int main ()
{
  A a = 'x';
  getchar ();
  return 0;
}

The result will be: “A (int)”
If we mark both explicit constructors for fencing purposes, then when:
A a ('x'); we still get the result above. Anyway, unnecessary (to us) transformation will occur.


Answer 1, authority 100%

It is needed not so much to call a specific constructor, but to avoid unnecessary casting (or unambiguous casting).

Roughly – imagine that the constructor of vector from int is not explicit . And we have

void f (vector & lt; & gt; ...);

Then the call to f (5) will also be a perfectly valid construction. It is unlikely that anyone needs it … Like

vector v;
v = 5;

By the way, Stroustrup writes that it would be nice if all the default constructors were explicit , and it was necessary to explicitly indicate the refusal of it.

Something like this.


Answer 2, authority 80%

A constructor without explicit allows you to implicitly convert the type of an argument to the type of the class that owns the constructor.

If we mark both explicit constructors for “fencing” purposes, then with: A a (‘x’); we will still get the result above.

Correct, because the entry A a ('x'); is direct-initialization for which is just the right explicit constructor. Those. there is an implicit conversion of type char to type int for the argument, but conversion to type A is already quite explicit.

What is the practical application?

Implicit conversions are dangerous, on the one hand they allow you to write fewer code letters , on the other hand, you can get not quite what you expect. Those. Looking at the code, we see one thing, but in the process of execution, something else happens. the implicit conversion happens, oddly enough, implicitly.

For example, in the situation with the already mentioned std :: vector , a constructor that accepts an integer is marked as explicit , because this integer specifies the size, although an uninitiated user would expect std :: vector & lt; int & gt; v = 5; rather than putting the number 5 into a vector, but certainly not creating a vector of five zero-initialized elements. Fortunately, explicit prevents such an entry from compiling.

Additionally, I want to note that before C++ 11 explicit , it was relevant to make only constructors that can be called with one argument. With the introduction of uniform initialization , this has become relevant for constructors that require multiple required arguments. For example:

struct A {
/ * explicit * / A (int, double, char) {}
};
A f () {
  return {42, 1.5, 'a'};
}
int main () {
  A a = {1, 2.0, 'b'};
}

not working yet explicit . If you make the constructor explicit, you will have to change the code:

A f () {
  return A {42, 1.5, 'a'};
}
int main () {
  A a = A {1, 2.0, 'b'};
  // or A a {1, 2.0, 'b'}; // direct initialization
}

By the way, although only constructors are mentioned in the question, explicit can be applied to conversion operators as well (starting with C++ 11 ):

struct A {
  explicit operator int () {return 42; }
};
int main () {
  A a;
  int j = a; // (1)
  int i = static_cast & lt; int & gt; (a); // (2)
  bool b = a; // (3)
  if (a) {// (4)
    // do something
  }
  else {
    // do another
  }
}

If operator int is not marked as explicit , then all code is fully functional. When we add explicit , only the string (2) remains valid. A little special in this case will look like operator bool () instead of operator int () :

struct A {
  explicit operator bool () {return true; }
};

With the explicit operator, only the (4) line will work, since using a variable in conditional expressions (if , while , ?: ) is interpreted as explicit conversion to bool . Without explicit , the code is still fully functional.


Answer 3, authority 47%

In addition to @Harry’s answer, and how to expand your comment:

class Foo
{
public:
  operator int () const
  {
    return 42;
  }
};
class Bar
{
public:
  Bar (Foo)
  {
  }
};
void baz (Bar)
{
}
void baz (int)
{
}
int main ()
{
  Foo x;
  baz (x);
}

Calling the baz function here will lead to ambiguity for the compiler, since it falls under both baz (int) and baz (Bar) . Adding explicit to the Bar constructor will give the compiler an unambiguous indication of which function to choose.

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions