Search code examples
c++c++11constructordefault-constructor

C++: no matching function for call: why is an empty constructor needed?


When I try to compile the following code:

class a {

  int i;

  public :
  a(int);
};

class b {
  a mya;  
  int j;

  public:
  b(int);

};

a::a(int i2) {
  i=i2;
}

b::b(int i2) {
  mya=a(i2); 
  j=2*i2;
}

int main() {

}

I get the following errors:

prog.cpp:21:12: error: no matching function for call to ‘a::a()

 b::b(int i2) {
            ^
prog.cpp:17:1: note: candidate: ‘a::a(int)

 a::a(int i2) {
 ^
prog.cpp:17:1: note:   candidate expects 1 argument, 0 provided
prog.cpp:1:7: note: candidate: ‘constexpr a::a(const a&)’
 class a {
       ^
prog.cpp:1:7: note:   candidate expects 1 argument, 0 provided
prog.cpp:1:7: note: candidate: ‘constexpr a::a(a&&)

prog.cpp:1:7: note:   candidate expects 1 argument, 0 provided

It seems that a constructor with no argument for the class a is expected. I do not understand why, the only time I create a object of type a, I call the constructor which takes an int as argument.

I understand that the solution would be to add a constructor without arguments for a. But why ?

Thank you for your answers, best regards,

Jerome


Solution

  • (All ISO Standard references below refer to N4659: March 2017 post-Kona working draft/C++17 DIS)


    As per [class.base.init]/9, the mya member of b, which is of type a, is default-initialized, but a defines no default constructor:

    In a non-delegating constructor, if a given potentially constructed subobject is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then

    • (9.1) if the entity is a non-static data member that has a default member initializer [...] the entity is initialized from its default member initializer as specified in [dcl.init];
    • (9.2) otherwise, if the entity is an anonymous union or a variant member ([class.union.anon]), no initialization is performed;
    • (9.3) otherwise, the entity is default-initialized.

    Here, as mya does is not declared along with a default member initializer, [class.base.init]/9.3 applies.

    The example of [class.base.init]/9 even cover this particular case:

    [...] [ Example:

    struct A {
      A();
    };
    
    struct B {
      B(int);
    };
    
    struct C {
      C() { }               // initializes members as follows:
      A a;                  // OK: calls A​::​A()
      const B b;            // error: B has no default constructor
      int i;                // OK: i has indeterminate value
      int j = 5;            // OK: j has the value 5
    };
    

    — end example ]

    You can resolve it either by providing a default member initializer for mya, such that [class.base.init]/9.1 applies

    class b {
      a mya{42};  // default member initializer
      int j;
    
      public:
      b(int);
    };
    

    or, use a member initializer list in the definition of the constructor of b; b::b(int), such that [class.base.init]/7 applies:

    The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of [dcl.init] for direct-initialization. [ Example:

    struct B1 { B1(int); /* ... */ };
    struct B2 { B2(int); /* ... */ };
    struct D : B1, B2 {
      D(int);
      B1 b;
      const int c;
    };
    
    D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ }
    D d(10);
    

    — end example ] [...]

    thus direct-initializing the mya member:

    b::b(int i2) : mya(i2) {
               //  ^^^^^^^- member initializer list
      j=2*i2;
    }