Error: A delegating constructor cannot have other mem-initializers

95 Views Asked by At

I have the class as follows:

class A{
private:
    int a;
    int b;
    int c;
public:
    A(int a1){
        a1 >= 0 ? a = a1 : a = -1;
    }
    A(int a1, int b1, int c1) : A{ a1 }, b{ b1 }, c{ c1 } {} //<---------- this line gives the error
};

but this gives me the error "A delegating constructor cannot have other mem-initializers".

I ended up fixing the code and making it:

class A{
private:
    int a;
    int b;
    int c;
public:
    A(int a1){
        a1 >= 0 ? a = a1 : a = -1;
    }
    A(int a1, int b1, int c1) : A{ a1 } {
        b = b1;
        c = c1;
    }
};

And the error went away. My question is, WHY does this make the error go away? Why does the previous method not work?

2

There are 2 best solutions below

0
paddy On

As stated by others in comments, the reason is that this is how the language specification is defined. That's why you can get a compiler error with a helpful message describing the cause of the problem.

From [class.base.init]:

6. ... 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...

Now, as for your delegating constructor, I propose that you currently have this backwards. The constructor A(int) is in fact a short-hand for your otherwise complete version A(int, int, int). It makes more sense to delegate in the other direction, assuming you don't have a very special reason to not initialize b and c at all:

class A
{
    int a, b, c;

public:
    A(int a) : A(a, 0, 0) {}

    A(int a, int b, int c)
        : a{a >= 0 ? a : -1}
        , b{b}
        , c{c}
    {}
};

Note also that you don't need to add random suffixes to your identifiers in an attempt to avoid name collisions. See the following:

From [class.base.init]:

2. Lookup for an unqualified name in a mem-initializer-id ignores the constructor's function parameter scope.

15. [Note 7: The expression-list or braced-init-list of a mem-initializer is in the function parameter scope of the constructor and can use this to refer to the object being initialized. — end note]

In short, a{a >= 0 ? a : -1} initializes the member a, and all the a identifiers inside the initializer list refer to the function parameter a.

0
David Schwartz On
class A{
private:
    int a;
    int b;
    int c;

Okay, so an A contains an a, a b, and a c.

    A(int a1, int b1, int c1) : A{ a1 }, b{ b1 }, c{ c1 } {} //<---------- this line gives the error

After A{ a1 }, you've initialized an A. Since an A contains an a, a b, and a c, initializing an A means we've already initialized an a, a b, and a c. So why are you trying to initialize b and c a second time? What would that do?