Reputation: 135
I am trying to overload a multiplication operator but do not want to type out multiple overloaded functions to take into account multiplying int and float, int and double, float and int, etc... I was hoping to write one overloaded operator to account for all combinations of multiplication with floats, ints, and doubles and get the proper return type. I am getting errors saying that no operator found which takes a right-hand operand of type 'Widget::Widget' (or there is no acceptable conversion). I think this is because I am using the decltype to set the template type of the return object, the Widget. Using a trailing return type works if the return is not a template object.
Here is an example of the overloaded operator I am trying to make:
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;
}
And here is an example of the template class
template<typename T> class Widget
{
private:
T x;
public:
Widget();
~Widget();
void SetX(T value);
Widget<T>& operator=(const Widget<T>& aWidget);
}
Example 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
}
Upvotes: 9
Views: 14275
Reputation: 7637
Reading the error message carefully, the problem is obvious:
candidate template ignored: substitution failure [with T1 = int, T2 = float]: 'x' is
a private member of 'Widget<int>'
Non-member binary operator*
is trying to access private member x
in its declaration (and definition). Since you have a setter function, a plain solution is to also define a getter and only access member x
through this function:
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;
}
Another option would be to make operator*
a friend:
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;
}
or, make it a member function (thanks WhozCraig).
You will probably also need
typename std::decay<decltype(aWidge.x*bWidge.x)>::type
instead of just decltype(aWidge.x*bWidge.x)
.
Other options are
typename std::decay<decltype(std::declval<T1>()*std::declval<T2>())>::type
which bypasses the previous problem entirely (thanks Adam), or just
typename std::common_type<T1, T2>::type
which should fit for this purpose and is arguably the simplest form.
Upvotes: 5
Reputation: 1
Visual Studio 2012
Don't mind the sloppy code. It was a quick fix for code that didn't compile properly to begin with (nevermind the auto decltype problem).
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
}
Upvotes: 3