Search code examples
c++constructordefault-constructorexplicitexplicit-constructor

What is the purpose of "explicit" for a default constructor?


I recently noticed a class in C++0x that calls for an explicit default constructor. However, I'm failing to come up with a scenario in which a default constructor can be called implicitly. It seems like a rather pointless specifier. I thought maybe it would disallow Class c; in favor of Class c = Class(); but that does not appear to be the case.

Some relevant quotes from the C++11 FCD, since it is easier for me to navigate [similar text exists in C++03, if not in the same places]

12.3.1.3 [class.conv.ctor]

A default constructor may be an explicit constructor; such a constructor will be used to perform default-initialization or value initialization (8.5).

It goes on to provide an example of an explicit default constructor, but it simply mimics the example I provided above.

8.5.6 [decl.init]

To default-initialize an object of type T means:

— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

8.5.7 [decl.init]

To value-initialize an object of type T means:

— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

In both cases, the standard calls for the default constructor to be called. But that is what would happen if the default constructor were non-explicit. For completeness sake:

8.5.11 [decl.init]

If no initializer is specified for an object, the object is default-initialized;

From what I can tell, this just leaves conversion from no data. Which doesn't make sense. The best I can come up with would be the following:

void function(Class c);
int main() {
  function(); //implicitly convert from no parameter to a single parameter
}

But obviously that isn't the way C++ handles default arguments. What else is there that would make explicit Class(); behave differently from Class();?

The specific example that generated this question was std::function [20.8.14.2 func.wrap.func]. It requires several converting constructors, none of which are marked explicit, but the default constructor is.


Solution

  • This declares an explicit default constructor:

    struct A {
      explicit A(int a1 = 0);
    };
    
    A a = 0; /* not allowed */
    A b; /* allowed */
    A c(0); /* allowed */
    

    In case there is no parameter, like in the following example, the explicit is redundant.

    struct A {
      /* explicit is redundant. */
      explicit A();
    };
    

    In some C++0x draft (I believe it was n3035), it made a difference in the following way:

    A a = {}; /* error! */
    A b{}; /* alright */
    
    void function(A a);
    void f() { function({}); /* error! */ }
    

    But in the FCD, they changed this (though, I suspect that they didn't have this particular reason in mind) in that all three cases value-initialize the respective object. Value-initialization doesn't do the overload-resolution dance and thus won't fail on explicit constructors.