Using base class operator= overload not building
Asked Answered
L

2

6

In this example code, why isn't using IParameterBase<TYPE>::operator=; working, and the base class assignment operator working?

I recently changed to this templated version, previously I had written individual type classes where this mechanism worked.

#include <cstdint>
#include <cstddef>
    
    class IParameter
    {
    public:
        explicit IParameter(const size_t size) : size_{size} {};
        virtual ~IParameter() = default;

        virtual void copy(uint8_t*& addr) = 0;
    private:
        const size_t size_;
    };

    template <class TYPE>
    class IParameterBase : public IParameter
    {
    public:
        explicit IParameterBase(const TYPE value) : IParameter{sizeof(TYPE)}, value_{value} {};
        ~IParameterBase() = default;

        virtual void update(const TYPE value) = 0;

        operator auto() const {return get();};

        TYPE operator= (const TYPE value) { update(value); return get(); };

        TYPE get() const {return value_;};

        protected:
        TYPE value_;
    };

    template <class TYPE>
    class ParameterTx : public IParameterBase<TYPE>
    {
    public:
        explicit ParameterTx(const TYPE value) : IParameterBase<TYPE>{value} {};

        using IParameterBase<TYPE>::operator=;

        void copy(uint8_t*& addr) override
        {
            /* copy stuff */
        }
        void update(const TYPE value) override
        {
            this->value_ = value;
        }
    };


int main ()
{
    ParameterTx<uint16_t> param1{0};
    ParameterTx<uint16_t> param2{1};

    param1 = 16;
    param2 = 5;

    param1 = param2;
}

Code here: https://godbolt.org/z/3vqd4ebYM

I expect the assignment at the bottom param1 = param2; to resolve to uint16_t, instead it's trying to copy the object, which is not what I want.

Lucifer answered 3/10 at 11:39 Comment(6)
"I expect the assignment at the bottom..." Kindly change "bottom" to the exact statement you're referring to.Nursling
"instead it's trying to copy the object...." Always post complete error along with your question. Many times the answer is in the error.Nursling
The problem is that IParameter has a const member, which makes it unassignable.Portuna
@Portuna OP already seem to know that. They're asking why the deleted version is choosen over the using IParameterBase<TYPE>::operator= version.Nursling
The answer is when you wrote param1 = param2 you're passing param2 which is of type ParameterTx<uint16_t> so only the deleted copy assignment operator= is a candidate because the one bought in by using IParameterBase<TYPE>::operator=; has a parameter of type const uint16_t valueNursling
Oh, the expectation is that param1 = param2; should be equivalent to param1 = static_cast<uint16_t>(param2);? It isn't, and implicit conversions are Evil. (Also, un-templating this code has the same problem.)Portuna
G
7

the compiler slipped in this extra function.

template <class TYPE>
class IParameterBase : public IParameter
{
public:
...
  TYPE operator= (const TYPE value) { update(value); return get(); };

   // this next one
  IParameterBase<TYPE>& operator= (const IParameterBase<TYPE>& value) = delete;
...
};

because the base IParameter is not copy-assignable as it has a const member.

With the code above the compiler is not allowed to compile the assignment param1 = param2 because the deleted assignment operator is an exact match, while the other one requires an implicit conversion.

the solution here is to undelete the deleted assignment operator inside IParameterBase

TYPE operator= (const IParameterBase<TYPE>& value) 
{ update(value.value_); return this->get(); };

godbolt demo

Geometric answered 3/10 at 12:14 Comment(2)
I see, so in this case the LHS is reaching in and taking the value from the RHS. I'll adapt that slightly and change value.value_ to value.get()Lucifer
@PaulSheppard it is copying the value from the RHS, yes.Geometric
N
4

why isn't using IParameterBase::operator=; working, and the base class assignment operator working? instead it's trying to copy the object.

Because when you wrote param1 = param2 you're passing param2 to the parameter of the assignment operator= and param2 is of type ParameterTx<uint16_t> so only the deleted copy assignment operator= is a candidate because the one bought in by using IParameterBase<TYPE>::operator=; has a parameter of type const uint16_t value.

And since the copy assignment operator is deleted because the base IParameter has a const member, we have the mentioned error.

To solve this you can either do explicit cast before passing param2 or allow the inherited operator=(via using) take part into overload resolution by undeleting the one from IParameterBase as done in other answer.

Nursling answered 3/10 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.