StoneThrow StoneThrow - 1 month ago 13
C++ Question

C++ initializer list capabilities: call functions without initializing member?

This is a question on the syntax of C++ initializer lists.

Is it possible to call functions from initializer lists without them being arguments to member object constructors?

Code example listed below is paraphrased (paracoded?) from a similar situation at work.

The Situation


  • A member variable takes a pointer to a singleton as constructor
    argument.

  • The member variable is constructed by initializer list in its containing class' constructor.

  • The singleton has not been created prior to the containing class being constructed.



The Code

#include <iostream>

#define LOG { std::cout << __PRETTY_FUNCTION__ << std::endl; }

namespace
{

template <class T>
class SingletonService
{
public:
static T* Instance() { LOG; return mpT; }
static void InstallInstance(T* pT) { LOG; mpT = pT; }
static void DeleteInstance() { if (mpT) delete mpT; }

protected:
static T* mpT;
};

template <class T>
T* SingletonService<T>::mpT = NULL;

class OneOfMe
{
public:
OneOfMe() { LOG; };
virtual ~OneOfMe() { };
};

class Container
{
public:
Container(OneOfMe* pObj) { LOG; /* Do something with pObj */ }
virtual ~Container() { }
};

int GenerateNum()
{
return 42;
}

class Baz
{
public:
Baz(int num) : mNum(num) { LOG; }
virtual ~Baz() { }
protected:
int mNum;
};

class Bar
{
public:
Bar() : mBaz(GenerateNum()) { LOG; } // Perfectly OK to call function that is argument to member object's non-default ctor.
virtual ~Bar() { };

protected:
Baz mBaz;
};

class Foo
{
public:
Foo()
: SingletonService<OneOfMe>::InstallInstance(new OneOfMe) // Compile error
, mContainer(SingletonService<OneOfMe>::Instance()) { }
virtual ~Foo() { };
protected:
Container mContainer;
};

}

int main(int argc, char* argv[])
{
LOG;
Bar bar;

SingletonService<OneOfMe>::InstallInstance(new OneOfMe); // This works.
Container container(SingletonService<OneOfMe>::Instance()); // And this works.
SingletonService<OneOfMe>::DeleteInstance();
return 0;
}


The compile error

>g++ main.cpp
main.cpp: In constructor ‘<unnamed>::Foo::Foo()’:
main.cpp:45: error: expected class-name before ‘(’ token
main.cpp:45: error: no matching function for call to
‘<unnamed>::Container::Container()’
main.cpp:37: note: candidates are:
<unnamed>::Container::Container(<unnamed>::OneOfMe*)
main.cpp:35: note:
<unnamed>::Container::Container(const<unnamed>::Container&)
main.cpp:45: error: expected ‘{’ before ‘(’ token


The Question

Is it syntactically possible to call a function from a class constructor's initializer list without being an argument to a member object's non-default constructor?

The question is for academic curiosity. I know at least one other solutions is to instantiate the singleton before creating the containing class.

Answer

You can utilize the comma operator.

In your example

class Foo
{
public:
    Foo()
        : mContainer((SingletonService<OneOfMe>::InstallInstance(new OneOfMe), SingletonService<OneOfMe>::Instance()))
    {}
    virtual ~Foo();
protected:
    Container mContainer;
};