Why is explicit allowed for default constructors and constructors with 2 or more (non-default) parameters?

Ashwin Nanjappa picture Ashwin Nanjappa · Dec 17, 2010 · Viewed 15.1k times · Source

I understand that constructors with one (non-default) parameter act like implicit convertors, which convert from that parameter type to the class type. However, explicit can be used to qualify any constructor, those with no parameters (default constructor) or those with 2 or more (non-default) parameters.

Why is explicit allowed on these constructors? Is there any example where this is useful to prevent implicit conversion of some sort?

Answer

Johannes Schaub - litb picture Johannes Schaub - litb · Dec 17, 2010

One reason certainly is because it doesn't hurt.

One reason where it's needed is, if you have default arguments for the first parameter. The constructor becomes a default constructor, but can still be used as converting constructor

struct A {
  explicit A(int = 0); // added it to a default constructor
};

C++0x makes actual use of it for multi parameter constructors. In C++0x, an initializer list can be used to initialize a class object. The philosophy is

  • if you use = { ... }, then you initialize the object with a sort of "compound value" that conceptually represents the abstract value of the object, and that you want to have converted to the type.

  • if you use a { ... } initializer, you directly call the constructors of the object, not necessarily wanting to specify a conversion.

Consider this example

struct String {
    // this is a non-converting constructor
    explicit String(int initialLength, int capacity);
};

struct Address {
    // converting constructor
    Address(string name, string street, string city);
};

String s = { 10, 15 }; // error!
String s1{10, 15}; // fine

Address a = { "litb", "nerdsway", "frankfurt" }; // fine

In this way, C++0x shows that the decision of C++03, to allow explicit on other constructors, wasn't a bad idea at all.