Reputation:
class Foo
{
public:
Foo() {}
Foo(int i)
: Foo(), m_bar(0) {}
private:
int m_bar;
};
Is there a workaround to making such code valid?
Is there a way to have more than one member in the initialization list if we have a delegating constructor, and what is the reason for such a restriction on having the delegating constructor be the only member in the initialization list.
Upvotes: 1
Views: 1864
Reputation: 73406
The rule that you refer to is defined in [class.base.init]/6
:
A mem-initializer-list can delegate to another constructor of the constructor’s class using any class-or-decltype that denotes the constructor’s class itself. If a mem-initializer-id designates the constructor’s class, it shall be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by the mem-initializer is the target constructor. The target constructor is selected by overload resolution. Once the target constructor returns, the body of the delegating constructor is executed. If a constructor delegates to itself directly or indirectly, the program is ill-formed, no diagnostic required.
Suppose a moment that the the delegate constructor could be used together with other mem-initializers:
Here an example to clarify the problem with a member that can be initialized only once, and solutions:
class Foo
{
const int m_bar; // can be initalized only once
int m_zoo; // must be constructed (default possible) but can be overwritten
public:
Foo(): m_bar(1), m_zoo(2) {} // the constant can never be changed
Foo(int i)
: Foo() {m_zoo=i;} // you can still change in the body already constructed items
Foo(int i, int j) // comprehensive init
: m_bar(i), m_zoo(j) {} // (has all that delegating may want(
Foo(char a)
: Foo(a,2) {}; // delegate to the comprehensive ctor
};
The delegation rule aims to keep all this simple. It just means that
So the way to make your design valid is to move all the mem-initilizer to the target constructor, and if needed use parameters of this target constructor to specify values for its mem-initializers. Or to overwrite in the body what was already initialized; but this is not always possible.
Upvotes: 3
Reputation: 30145
The problem is since the initializer list in a constructor must initialize every base and member (in declaration order) that has it's own constructor (default constructor if not otherwise specified), that : Foo()
must have already done so, and calling some members constructor twice would be bad.
I suppose you could argue in the case of primitives that might be left uninitialized that it could be allowed, but then in such cases assigning them within the function body would be equivalent.
Upvotes: 3