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:
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:
virtual void setValue(T value) { // -- (A)
m_state = value;
// (... more things.)
}
virtual void setValue(T&& value) { // -- (B)
m_state = value;
// (... more things.)
}
T getValue(void) { return m_state; }
protected:
T m_state;
};
template <class T>
class MOutput : public MState<T>
{
public:
void setValue(T value) override { // -- (C)
MState<T>::setValue(std::forward<T>(value));
// (... even more things.)
}
void setValue(T&& value) override { // -- (D)
MState<T>::setValue(std::forward<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).
The use of std::forward<T>(value)
in (C) and (D) is motivated by [3].
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?
GCC fails to compile the line MState<T>::setValue(std::forward<T>(value));
of both (C) and (D). If I comment them out, I get the same ambiguity error in these cases:
bool function(int a) { return a >= 1; }
MOutput<bool> vo0, vo1, vo2;
vo1.setValue(true); // Error.
vo2.setValue(false); // Error.
vo0.setValue(!(vo1.getValue() & vo2.getValue())); // Error.
MOutput<int> vo3;
vo3.setValue(432); // Error.
I would simply have simple void setValue(const T& value)
(even more when your getter does copy).
But if you want both l-value reference, and r-value reference, it would be something like:
template <class T>
class MState
{
public:
virtual void setValue(const T& value) {
m_state = value;
MoreStuff()
}
virtual void setValue(T&& value) {
m_state = std::move(value);
MoreStuff()
}
const T& getValue() const { return m_state; }
private:
void MoreStuff();
protected:
T m_state;
};
template <class T>
class MOutput : public MState<T>
{
public:
void setValue(const T& value) override {
MState<T>::setValue(value);
MoreThings();
}
void setValue(T&& value) override {
MState<T>::setValue(std::move(value));
MoreThings();
}
private:
void MoreThings();
};
Is T&& here a universal reference?
As state, in comment, no it isn't, T
is fixed by the class.