Представьте, что у вас есть простой объект 2D Point с двумя сеттерами и геттерами.
template <typename T>
class Point
{
public:
Point(T x, T y);
T getX() const;
T getY() const;
void setX(T x);
void setY(T y);
private:
T _x;
T _y;
};
Но я хочу работать с этим классом в более похожем на сценарии синтаксисе. Что-то вроде:
auto point = Point<double>(10, 10);
point.x = 20;
point.y = point.x + 10;
Вы скажете, просто используйте структуру с публичной переменной:
template <typename T>
struct Point
{
T x;
T y;
};
Да, но я хочу сохранить конфиденциальность параметров и расширить класс с помощью некоторых методов. Поэтому другая идея заключается в создании помощника-обертки, который добавляет псевдоним оператора в методы установки / получения:
template <typename T, typename Get, Get(T::*Getter)() const,
typename Set, void(T::*Setter)(Set)>
struct ReadWrite
{
ReadWrite(T& ptr) : ptr(ptr) {}
inline void operator= (Set const& rhs)
{
(ptr.*Setter)(rhs);
}
inline Get operator()()
{
return (ptr.*Getter)();
}
private:
T& ptr;
};
ОК, я просто изменяю свой класс Point для выполнения работы:
template <typename T>
class Point
{
public:
Point(T x, T y);
T getX() const;
T getY() const;
void setX(T x);
void setY(T y);
private:
T _x;
T _y;
public:
ReadWrite<Point<T>, T, &Point<T>::getX, T, &Point<T>::setX> x;
ReadWrite<Point<T>, T, &Point<T>::getY, T, &Point<T>::setY> y;
};
Добавив некоторые арифметические операторы (+ - * /), я могу использовать это так:
auto point = Point<double>(10, 10);
point.x = 20;
point.y = point.x + 10;
Здесь point.x
нормально в случае перегрузки оператора в виде:
template <typename T, typename V> inline T operator+(ReadWrite<T> const& lhs, V const& rhs) { return lhs() + rhs; }
template <typename T, typename V> inline T operator-(ReadWrite<T> const& lhs, V const& rhs) { return lhs() - rhs; }
template <typename T, typename V> inline T operator*(ReadWrite<T> const& lhs, V const& rhs) { return lhs() * rhs; }
template <typename T, typename V> inline T operator/(ReadWrite<T> const& lhs, V const& rhs) { return lhs() / rhs; }
Если я хочу использовать этот синтаксис, но без скобок на point.x
getter:
auto point = Point<double>(10, 10);
auto x = point.x();
Я расширяю помощника ReadWrite:
template <typename T, typename Get, Get(T::*Getter)() const,
typename Set, void(T::*Setter)(Set)>
struct ReadWrite
{
ReadWrite(T& ptr) : ptr(ptr) {}
inline void operator= (Set const& rhs)
{
(ptr.*Setter)(rhs);
}
inline Get operator()()
{
return (ptr.*Getter)();
}
inline operator auto() -> Get
{
return operator()();
}
private:
T& ptr;
};
Теперь без скобок:
double x = point.x; // OK, x is my x value (Point).
auto x = point.x; // Wrong, x is my ReadWrite<T> struct.
Что не так с перегрузкой оператора auto
?
Большое спасибо за ваш ответ.