dimanche 1 novembre 2020

No inheritance found with operator= and initializer_list

Here the code that I a lot simplify for this question.

template<class T>
class A
{
public:

    A<T>& operator=(A<T> const& other)
    {
        std::cout << "A<T>& operator=(A<T> const& other)\n";
        return this->operator=(other.m_container);
    }

    template<class U>
    A<T>& operator=(std::vector<U> const& other)
    {
        std::cout << "A<T>& operator=(std::vector<U> const& other)\n";
        // Code not shown: m_container = other;
        return *this;
    }

    A<T>& operator=(std::initializer_list<T> il)
    {
        std::cout << "A<T>& operator=(std::initializer_list<T> il)\n";
        // Code not shown: m_container = il;
        return *this;
    }

    std::vector<T> m_container;
};

//
template<typename T>
class B: public A<T>
{};

Initially I believed it was an issue with template but this does not change facts. So here the simplified classes for my question:

class AA
{
public:

    AA& operator=(AA const& other)
    {
        std::cout << "AA& operator=(AA const& other)\n";
        return this->operator=(other.m_container);
    }

    AA& operator=(std::vector<float> const& other)
    {
        std::cout << "AA& operator=(std::vector<float> const& other)\n";
        // Code not shown: m_container = other;
        return *this;
    }

    AA& operator=(std::initializer_list<float> il)
    {
        std::cout << "AA& operator=(std::initializer_list<float> il)\n";
        // Code not shown: m_container = il;
        return *this;
    }

    std::vector<float> m_container;
};

//
class BB: public AA
{};

My question is that I'm not totally sure to understand why:

BB bb1;
bb1 = { -1.0f, -1.0f, 0.0f };

is not compiling:

In function ‘int main()’:
error: no match for ‘operator=’ (operand types are ‘BB’ and ‘<brace-enclosed initializer list>’)
     bb1 = { -1.0f, -1.0f, 0.0f };
                                ^
note: candidate: ‘BB& BB::operator=(const BB&)’
     BB& operator=(BB const& other)
         ^~~~~~~~
note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const BB&’

While the following modification, the code is working:

class BB: public AA
{
public:

    BB& operator=(std::initializer_list<float> il)
    {
        std::cout << "BB& operator=(std::initializer_list<float> il)\n";
        AA::operator=(il);
        return *this;
    }
};

Result:

BB& operator=(std::initializer_list<float> il)
AA& operator=(std::initializer_list<float> il)

This is particularly strange because the following code is not impacted (the inheritance is well called):

BB bb1;
BB bb2;
bb2 = bb1;

Result:

AA& operator=(AA const& other)
AA& operator=(std::vector<float> const& other)

So no need to change the class to:

class BB: public AA
{
public:

    BB& operator=(BB const& other)
    {
        std::cout << "BB& operator=(BB const& other)\n";
        AA::operator=(other.m_container);
        return *this;
    }

    BB& operator=(std::initializer_list<float> il)
    {
        std::cout << "BB& operator=(std::initializer_list<float> il)\n";
        AA::operator=(il);
        return *this;
    }
};

At first, I thought it was because I had to call base<T>::method() from a template derived class that was why I had to create a derived<T>::method() calling the base but this is not the reason. Ideally I would like avoiding creating BB& operator=(std::initializer_list<float> il) that looks like a useless copy/past code to me.

Thanks in advance!

Aucun commentaire:

Enregistrer un commentaire