Pregunta

I have a struct A that has several constructors with different data members initialized.

template<typename T>
    struct A {

    typedef std::vector<T> type1
    type1 a;
    type1 b;
    type1 c;

    A(type1 i_a): a(i_a) {
    }

    A(type1 i_a, type1 i_b): A(i_a), b(i_b) {
    }

    A(type1 i_a, type1 i_b, type1 i_c): A(i_a, i_b), c(i_c) {
    }
};

Error I get is when I instantiate it with say custom_type, the error is type A<custom_type> is not direct base of A<custom_type> highlighting the constructor I call within another constructor. I am using C++11. What's the problem?

¿Fue útil?

Solución

A constructor may initialize its base classes and members, OR delegate to another constructor of the same class, not both.

A(i_a) constructs a complete A object, copying member a and default-constructing b and c. So it doesn't make sense to have A(type1 i_a, type1 i_b): A(i_a), b(i_b) {} - the first initializer has already initialized b. You could instead have

A(type1 i_a, type1 i_b) : A(i_a) { b = std::move(i_b); }

Otros consejos

aschepler provides the answer but I wanted to explain what lead to the problem and show 'best practices' for delegating constructors to avoid it.

In your code you have a series of constructors, each more general than constructor they delegate to. That is you're trying to have a constructor delegate to a more specialized constructor that doesn't do everything and then you tack on a bit of work to handle the extra generality. This is backwards from what has turned out to be the most practical way of construction delegation in earlier languages that support it.

What you want instead is to have the most general constructor be the 'root' of the delegation (the 'designated initializer' or 'designated constructor', in other languages). More specialized constructors will do their work using more general constructors, passing them the data for the special case to be handled.

In your case the specialized behavior is to use default values for some members instead of taking initial values from the user. So your more specialized constructors will do their work by passing on the parameter they're given along with default values for the other members.

template<typename T>
struct A
{
    typedef std::vector<T> type1;
    type1 a;
    type1 b;
    type1 c;

    A(type1 i_a, type1 i_b, type1 i_c): a(i_a), b(i_b), c(i_c) {}

    A(type1 i_a, type1 i_b): A(i_a, i_b, {}) {}

    A(type1 i_a): A(i_a, {}) {}
};

but you can still call different constructors of the same class from the body of constructor (if for some reason you would want to)

class CComplex{
public:
    CComplex(int real1,int image1,char c)
    {
        cout<<"RealImg";
        real=real1;
        image=image1;
        char* x; char xc=c;x=&xc;
        void* v;
        f(x);
        CComplex ccc(x,v); //this is OK
        CComplex cccc(1,2,3); //as this too
    }
    CComplex():real(0),image(0){cout<<"DEFAULT";}
    CComplex(const CComplex &c)
    {
        real=c.real;
        image=c.image;
        cout<<"COPY";
    }
    CComplex& operator=(CComplex const& ref){ 
        cout<<"ASSIGN";
        //CComplex* c;
        CComplex cobj(43,45,'x');
        //c=&cobj;
        //CComplex* c=new CComplex(44,45); 
        return cobj;
    }

    CComplex(int i1, int i2, int i3){cout<<"\n123!";}
    CComplex(const char* y,void* v){cout<<"\nCrefvoid!";}
    ~CComplex(){cout<<"\n~CComplex(){}";}
public:
    void Display(void)
    {
        cout<<real<<"+"<<image<<"i"<<endl;
    }
    static bool CComplexComparator(CComplex c1, CComplex c2){return true;}
    static void CComplexInit(CComplex& c){
        c.real=100;
    }
    int real,image;
}; 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top