1

I read about references and objects that are initialised in a class. However, I couldn't find a clear statement, except for hints, to the following question:

Can I initialise a member object obj1 in an initialisation list if it doesn't have a default constructor (no Object(){})?

class Sample
{
private:
      Object1 obj1(arguments);
public:
     Sample(Object1 o1)  : obj1( o1(arguments) )
     { }
};

The question came up, because if have a problem related to this How can I initialize C++ object member variables in the constructor?. The code is taken form there as well. Thanks for your effort.

Daniel

EDIT:

Since the answer suggest that it works, a test returned an error (which is exactly the reason I ask this question):

../src/Timestep.h:45:12: error: field ‘myFEMSolver’ has incomplete type FEMSolver myFEMSolver;

Code:

class Timestep {
public:
  Timestep();
private:
  FEMSolver myFEMSolver;
}

Timestep::Timestep() : myFEMSolver(*this)
  { //do some stuff
}

FEMSolver::FEMSolver(const Timestep& theTimestep) : myTimestep(theTimestep)
  { //do some stuff
}

main(){
  Timestep myTimestep();
}
Community
  • 1
  • 1
dani
  • 3,677
  • 4
  • 26
  • 60
  • 1
    That code does not produce that error. Namely, you get that error when the `FEMSolver` class itself is declared but not defined at the point that `TimeStep` is defined. `FEMSolver` must be defined fully first. This has nothing whatsoever to do with initializer lists. http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Mooing Duck Mar 25 '14 at 19:12
  • In fact it is not a XY problem. The original question was important to realise that what I intend to do would actually work. But you were right about the declaration. I switched come header an now it works. Thanks you very much. – dani Mar 25 '14 at 20:21
  • X was "what is producing this incomplete type error". Y is "Can I initialize a member object in an initialization list if it doesn't have a default constructor " This is _very much_ an X/Y problem. – Mooing Duck Mar 25 '14 at 20:26

3 Answers3

6

Can I initialise a member object obj1 in an initialisation list if it doesn't have a default constructor (no Object(){})?

Yes. In fact, you must do so.

class Sample
{
    private:

        Object1 obj1;

    public:

        Sample() : obj1( /* ctor args */ )
        {
        }
};

If you're passing another Object1 to your Sample constructor, and passing that to Object1's copy constructor, then you probably want to pass it by reference:

Sample(const Object1& o) : obj1(o)
{
}

If Object1 doesn't have a no-argument constructor, and you don't initialize obj1 in the initializer list, you'll get a compile error.

TypeIA
  • 16,916
  • 1
  • 38
  • 52
0

Change your class declaration as follows:

class Sample
{
private:
      Object1 obj1;
public:
     Sample(const Object1& o1)  : obj1(o1)
     { }
};

To call the Sample constructor use:

Sample s(Object1(arguments));

This requires, that your Object1 is a so called nice class (provides copy constructor and assignment operator).
For any other case you'll need to use a reference or pointer of Object1 as member in the Sample class.

Another (easier) way is to pass the arguments through:

class Sample
{
private:
      Object1 obj1;
public:
     Sample(Args& arguments)  : obj1(arguments)
     { }
};
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
0

It appears you either want to give an existing Object1 in a list-initializer, or make an Object1 inside a nested list-initializer, unless Object1's constructor is explicit. So let's say we have

struct Object1
{
    Object1(int, int) { };
};

Then the most generic way to initialize Object1 within Sample by copy, move, or its own arguments without ambiguities is:

class Sample
{
private:
    Object1 obj1;
public:
    Sample(Object1&& o1) : obj1(std::move(o1)) { }
    Sample(const Object1& o1) : obj1(o1) { }

    template<
        typename... A,
        typename = typename std::enable_if<std::is_constructible<Object1, A...>{}>
    >
    Sample(A&&... a) : obj1(std::forward<A>(a)...) { }
};

This allows us a variety of Sample constructions:

int main ()
{
    Object1 o1{1, 2};
    const Object1& o2{o1};
    Sample s1{Object1{1, 2}};
    Sample s2{{1, 2}};
    Sample s3{1, 2};
    Sample s4{o1};
    Sample s5{o2};
}

If Object1's constructor is explicit, then s2 is not allowed. Depending on what you want to support, you can of course simplify Sample in a number of ways.

iavr
  • 7,547
  • 1
  • 18
  • 53