我有一个与引用转发有关的问题,对此我只是稍微熟悉。在陈述我的问题之前,我想说我已经阅读了一些与此语言功能相关的页面,它们让我感到困惑,而不是阐明我的问题。参考的参考文献是:[ 1 - 5 ],其中一些我觉得矛盾或不完全理解。意识到这个问题可能被认为是重复的事实,我还是发布了它,因为我找不到一个可以结合这三个因素的案例:
- 具有 r 值引用的重载函数。
- 模板类(不是函数)。
- 在覆盖中调用父类的函数的重载函数的覆盖。
问题场景
我有两个类用于表示模型的变量。通用的是MState<T>
,我将它模板化,因为我希望它包含任何可能的类型。它更像是我为与此问题无关的目的而创建的类型的包装器。然后,我有MOutput<T>
,它本质上扩展MState<T>
并表示用户定义模型的外部可见变量。
它们都有一个名为的成员函数setValue
,它允许,嗯……设置它们的值。我知道实现运算符语义会很好,但现在我正在处理这个:
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.)
}
};
我认为我需要 (A) 允许 l 值成为调用中的有效参数MState::setValue
。实际上,如果我删除它,编译器会抱怨它无法将左值引用转换为右值引用(我理解为 [ 4 ]。)但是,我想避免不必要的资源分配和复制,尤其是在处理临时文件时(例如ms.setValue(MyClass())
。)因此(B)。
同样, (C) 是必要的,因为MOutput
除了那些工具之外,我还需要 's 做更多的事情MState
。对于上述相同的动机,我也想要(D)。
std::forward<T>(value)
(C) 和 (D) 中的使用是由 [ 3 ] 推动的。
问题
当我尝试编译我的代码时,GCC 抱怨重载的函数签名在两个类和许多情况下都是模棱两可的。我想我不明白为什么,或者如何解决这个问题。T&&
这里是通用参考吗?如果是这样,这些不应该接受任何类型的参数类型吗?
用例
GCC 无法编译MState<T>::setValue(std::forward<T>(value));
(C) 和 (D) 的行。如果我将它们注释掉,在这些情况下我会得到同样的歧义错误:
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.