Ghostkeeper
Ghostkeeper

Reputation: 3050

Can't initialize field outside initializer list

I'm having trouble with something that seems very easy, so I must be overlooking something.

I need to construct a class that has a field that is also a class (non-POD). The class of the field has a default constructor and a "real" constructor. The thing is that I really can't construct the field in the initializer list, because in reality the constructor has a parameter that is a vector which needs a somewhat complex for loop to fill.

Here is a minimal example that reproduces the problem.

ConstructorsTest.h:

class SomeProperty {
public:
    SomeProperty(int param1); //Ordinary constructor.
    SomeProperty();           //Default constructor.
    int param1;
};

class ConstructorsTest {
    ConstructorsTest();
    SomeProperty the_property;
};

ConstructorsTest.cpp:

#include "ConstructorsTest.h"

ConstructorsTest::ConstructorsTest() {
    the_property(4);
}

SomeProperty::SomeProperty(int param1) : param1(param1) {}
SomeProperty::SomeProperty() : param1(0) {} //Default constructor, doesn't matter.

But this gives a compile error:

ConstructorsTest.cpp: In constructor 'ConstructorsTest::ConstructorsTest()':
ConstructorsTest.cpp:4:19: error: no match for call to '(SomeProperty) (int)'
    the_property(4);
                  ^

It gives no suggestions like it usually would of what functions could have been intended instead.

In the above example I would just initialize the_property in the initializer list, but in reality the 4 is actually a complex vector that needs to be generated first, so I really can't. Moving the_property(4) to the initializer list causes the compilation to succeed.

Other similar threads mention that the object must have a default constructor, or that it can't be const. Both requirements seem to have been met, here.

Upvotes: 3

Views: 2006

Answers (2)

songyuanyao
songyuanyao

Reputation: 172864

You can't initialize data member inside the constructor's body. (the_property(4); is just trying to invoke the_property as a functor.) You can only assign them like:

ConstructorsTest::ConstructorsTest() {
    the_property = ...;
}

but in reality the 4 is actually a complex vector that needs to be generated first

You can add a member function which generate the necessary data, and use it to initialize the data member in member initializer list. e.g.

class ConstructorsTest {
    ...
    static int generateData();
};

int ConstructorsTest::generateData() {
    return ...;
}

ConstructorsTest::ConstructorsTest() : the_property(generateData()) {
}

Upvotes: 3

Nicol Bolas
Nicol Bolas

Reputation: 473222

You cannot initialize a variable twice.1 When your constructor has started, all member subobjects will have been constructed. If you do not provide a member initializer in the constructor, or a default member initializer in the class definition, then it will perform default initialization. Regardless of what form it takes, you can't construct it again.

Complex multi-statement initialization is best done via a lambda function:

ConstructorsTest::ConstructorsTest()
  : the_property( []{ /* Do Complex Initialization */}() )
{
}

1: Well... you can, but not like that. And you really shouldn't for cases as simple as this.

Upvotes: 1

Related Questions