vendredi 22 juin 2018

Why call to overloaded overridden function with universal or r-value reference is ambiguous?

I have a problem related to reference forwarding, to which I am only slightly familiar with. Before stating my question, I want to say that I've read a few pages related to this language feature and they kind of confused me rather than shedding light into my problem. The consulted references are: [1-5], some of which I find contradictory or don't fully understand. Aware of the fact that this question could be considered a duplicate, I am posting it anyways because I couldn't find a case that would combine these three factors:

  • Overloaded functions with r-value references.
  • Templated classes (not functions).
  • Override of overloaded functions where the parent class' function is called in the overrides.

Problem scenario

I have two classes that I use to represent a variable of a model. The generic one is MState<T> and I template it because I want it to wrap any possible type inside. It's more like a wrapper to a type that I have created for a purpose which is irrelevant to this question. Then, I have MOutput<T>, which essentially extends MState<T> and represents an externally visible variable of a user-defined model.

They both have a member function called setValue which allows to, well... set their value. I know it would be nices to implement operator semantics, but for now I'm dealing with this:

template <class T>
class MState : public MVariable
{
public:
    virtual void setValue(T value) {      // -- (A)
        m_state = value;
        // (... more things.)
    }
    virtual void setValue(T&& value) {    // -- (B)
        m_state = value;
        // (... more things.)
    }
protected:
    T m_state;
};

template <class T>
class MOutput : public MLinkedOVariable, public MState<T>
{
public:
    void setValue(T value) override {                     // -- (C)
        MState<T>::setValue(static_cast<T&&>(value));
        // (... even more things.)
    }
    void setValue(T&& value) override {                   // -- (D)
        MState<T>::setValue(static_cast<T&&>(value));
        // (... even more things.)
    }
};

I think I need (A) to allow for l-values to be valid arguments in calls to MState::setValue. Actually, if I remove it the compiler complains that it cannot convert an l-value to an r-value reference (which I understood with [4].) However, I want to avoid unnecessary resource allocations and copies, especially when dealing with temporaries (e.g. ms.setValue(MyClass()).) Hence (B).

Likewise, (C) is necessary because I need MOutput's to do a few things more, in addition to the ones MState implements. For the same motivation above, I also want (D).

Question

When I try to compile my code, GCC complains about the overloaded function signature to be ambiguous in both classes and a number of cases. I think I don't understand why, or how to solve the issue. Is T&& here a universal reference? If so, shouldn't these accept any kind of argument type?

Consulted references

  1. https://www.codesynthesis.com/~boris/blog/2012/06/26/efficient-argument-passing-cxx11-part2/
  2. https://stackoverflow.com/a/31551595/1876268
  3. https://stackoverflow.com/a/3582313/1876268
  4. https://stackoverflow.com/a/40350289/1876268
  5. https://stackoverflow.com/a/5465371/1876268

Aucun commentaire:

Enregistrer un commentaire