我试图重载一个乘法运算符但是不想输出多个重载函数来考虑乘以int和float,int和double,float和int等等...我希望写一个重载运算符考虑乘法与浮点数,整数和双精度的所有组合,并获得正确的返回类型。我收到错误,说没有运算符发现哪个采用'Widget :: Widget'类型的右手操作数(或者没有可接受的转换)。我想这是因为我使用decltype来设置返回对象的模板类型Widget。如果返回不是模板对象,则使用尾随返回类型。
以下是我尝试重载运算符的示例:
template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge) -> Widget<decltype(aWidge.x*bWidge.x)>
{
Widget<decltype(aWidge.x*bWidge.x)> result;
//do stuff needed when multiplying two Widgets
return result;
}
template<typename T>
Widget<T>& Widget<T>::operator=(const Widget<T>& aWidget)
{
x = aWidget.x;
return *this;
}
以下是模板类
的示例template<typename T> class Widget
{
private:
T x;
public:
Widget();
~Widget();
void SetX(T value);
Widget<T>& operator=(const Widget<T>& aWidget);
}
示例Main.cpp
int main()
{
Widget<int> aWidge;
Widget<float> bWidge;
Widget<float> cWidge;
aWidge.SetX(2);
bWidge.SetX(2.0);
cWidge = aWidge*bWidge; //this should give a float return type
}
答案 0 :(得分:4)
仔细阅读错误信息,问题很明显:
candidate template ignored: substitution failure [with T1 = int, T2 = float]: 'x' is
a private member of 'Widget<int>'
非成员二进制文件operator*
正试图在其声明(和定义)中访问私有成员x
。由于你有一个setter函数,一个简单的解决方案是通过这个函数定义一个getter并且只访问成员x
:
template<typename T> class Widget
{
private:
T x;
public:
Widget() {}
~Widget() {}
void SetX(T value) {}
T& GetX() { return x; }
const T& GetX() const { return x; }
Widget<T>& operator=(const Widget<T>& aWidget);
};
template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
-> Widget<decltype(aWidge.GetX()*bWidge.GetX())>
{
Widget<decltype(aWidge.GetX()*bWidge.GetX())> result;
//...
return result;
}
另一个选择是让operator*
成为朋友:
template<typename T> class Widget
{
private:
T x;
template<typename T1, typename T2>
friend auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
-> Widget<decltype(aWidge.x*bWidge.x)>;
public:
Widget() {}
~Widget() {}
void SetX(T value) {}
Widget<T>& operator=(const Widget<T>& aWidget);
};
template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
-> Widget<decltype(aWidge.x*bWidge.x)>
{
Widget<decltype(aWidge.x*bWidge.x)> result;
return result;
}
或者,使其成为会员功能(感谢WhozCraig)。
您可能还需要
typename std::decay<decltype(aWidge.x*bWidge.x)>::type
而非decltype(aWidge.x*bWidge.x)
。
其他选项
typename std::decay<decltype(std::declval<T1>()*std::declval<T2>())>::type
完全绕过上一个问题(感谢Adam),或者只是
typename std::common_type<T1, T2>::type
应该适合这个目的,可以说是最简单的形式。
答案 1 :(得分:3)
Visual Studio 2012
不要介意草率的代码。对于没有正确编译的代码,这是一个快速修复(永远不要解决自动decltype问题)。
template<typename T>
class Widget
{
public:
T x;
public:
Widget()
: x(666)
{}
~Widget() {}
void SetX(T value)
{
x = value;
}
Widget<T>& operator=(const Widget<T>& aWidget)
{
x = aWidget.x;
return *this;
}
};
template<typename T1, typename T2>
auto operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge) -> Widget<typename std::remove_const<decltype(aWidge.x*bWidge.x)>::type>
{
Widget<typename std::remove_const<decltype(aWidge.x*bWidge.x)>::type> result;
result.x = aWidge.x * bWidge.x;
return result;
}
int main ()
{
Widget<int> aWidge;
Widget<float> bWidge;
Widget<float> cWidge;
aWidge.SetX(2);
bWidge.SetX(2.0);
cWidge = aWidge*bWidge; //this should give a float return type
}