У меня проблема с перегрузкой оператора + шаблонный класс.
Предположим, у меня есть
template<typename T>
struct point{
//Ctors:
point(){};
point(T _x, T _y):x(_x),y(_y){};
point(const point<T>& p):x(p.x),y(p.y){};
template<typename T2>
point(const point<T2>& p):x(static_cast<T>(p.x)),y(static_cast<T>(p.y)){};//Coordinates:
T x;
T y;//Operator overloads:
friend point<T> operator+(point<T> left,point<T> right ){
return point<T>(left.x+right.x, left.y+right.y);
}
template<class T2>
friend point<T> operator+(point<T2> left,point<T> right){
return point<T>(left)+right;
}
template<class T3>
friend point<T> operator+(point<T> left,point<T3> right){
return point<T>(right)+left;
}};
Это дает мне ошибку неоднозначности при звонке.
point<float> p1(1.2,1.4);
point<int> p2(1,2);
point<float> p3 =p1+p2;
Это имеет смысл, но можете ли вы рассказать мне хорошую практику, как это исправить?
Мне нужно 3 оператора, так как в противном случае приведение может идти в неправильном направлении. Например, игнорирование последней перегрузки оператора приведет к p3.x=2
а также p3.y=4
,
Большое спасибо!
В некоторой степени это вопрос личных предпочтений и субъективного мнения, но я думаю, что я попытался бы подражать обычным правилам C ++ для типов результатов арифметических выражений, например,
template <class T1, class T2 >
friend
auto operator+( Point<T1> const left, Point<T2> const right )
-> Point< decltype( left.x + right.x ) >
{
return {left.x + right.x, left.y + right.y};
}
Удовлетворение как g ++ 4.8.2, так и visual c ++ 12.0 оказалось сложнее, чем я себе представлял, но вот конкретный код, который безошибочно компилируется с обоими этими компиляторами:
#include <type_traits>
#include <utility>
template< class Number >
struct Point
{
Number x;
Number y;
};
template< class T1, class T2 >
auto operator+( Point<T1> const left, Point<T2> const right )
-> Point< typename std::remove_const<decltype( left.x + right.x )>::type >
{
using Result_number =
typename std::remove_const<decltype( left.x + right.x )>::type;
using Result_point = Point< Result_number >;
return Result_point{ left.x + right.x, left.y + right.y };
}
auto main()
-> int
{
Point<float> const p1{ 1.2, 1.4 };
Point<int> const p2{ 1, 2 };
Point<float> const p3 = p1 + p2;
}
Чтобы облегчить возможное сужение конверсий Point
Вы можете добавить функцию-член оператора явного преобразования, например так:
template< class Number >
struct Point
{
Number x;
Number y;
template< class Other_number >
explicit
operator Point<Other_number>() const
{
return Point<Other_number>{
static_cast<Other_number>( x ),
static_cast<Other_number>( y )
};
}
};
Для вызова используйте любой подходящий актерский состав, например, очевидная нотация конструктора (которая с приведенными выше определениями является просто приведением, вызывающим оператор преобразования):
Point<int> const p4 = Point<int>( p1 + p2 );
Если вы хотите иметь результат в типе параметра результата, то создайте метод для его вычисления:
template<class T, class T2, class T3>
void AddPoints(const point<T>& a, const point<T2>& b, point<T3>& result)
{
result = point<T3>(a) + point<T3>(b);
}
int main()
{
point<float> p1(1.2,1.4);
point<int> p2(1,2);
point<double> result;
AddPoints(p1, p2, result);
}