"Adapter" for member variables

Typically, the purpose of the adapter is to make function calls in a modified format. Is there a way to do the same for member variables? That is, let's say I have an object containing SomePoint and another object containing DifferentPoint . SomePoint stores its data as member variables, capitalized in X and Y , where AnotherPoint stores the data as member variables in lowercase X and X Therefore, the problem is that you cannot write a function that accepts either SomePoint or DifferentPoint , because you cannot access .x or .x (even using templates without specializing completely for each type of points, in this case you can just overload the point type).

The question is, is there a way to make an adapter that will produce .x for SomePoint when .x requested? Both of these point types are library classes, so I cannot edit internal elements myself. I would also like to avoid copying data.

+5
source share
4 answers

The usual way to do this is to write a feature class to indicate how to output the data you need.

An implementation using a member-to-member pointer is possible here. You could make them functions or lambdas if you want.

 template <typename T> struct PointTraits; template <> struct PointTraits<SomePoint> { constexpr static auto getX = &SomePoint::x; constexpr static auto getY = &SomePoint::y; }; template <> struct PointTraits<AnotherPoint> { constexpr static auto getX = &AnotherPoint::X; constexpr static auto getY = &AnotherPoint::Y; }; 

Then you will use it as follows:

 template <typename PointT> void printX (const PointT& point) { std::cout << point.*PointTraits<T>::getX; } 
+9
source

Based on what is said TartanLlama, you can use the free function, akin to std::tuple and its get <>.

 #include <tuple> #include <type_traits> #include <iostream> struct SomePoint { double x; double y; }; namespace adapter { template <typename T> struct PointTraits; template <> struct PointTraits<SomePoint> { constexpr static auto getters = std::make_tuple(&SomePoint::x, &SomePoint::y); }; const unsigned X = 0; const unsigned Y = 1; template< unsigned C, class Point, class Traits = PointTraits< std::remove_reference_t<std::remove_cv_t<Point>> > > constexpr decltype(auto) get (Point&& p) { return std::forward<Point>(p).*(std::get<C>(Traits::getters)); } } int main() { using namespace adapter; SomePoint sp {1, 2}; std::cout << get<X>(sp) << '\n' << get<Y>(sp) << std::endl; return 0; } 
+1
source

Write a Point adapter class that has implicit conversion syntax for both target types. Note that data must be copied, therefore not ideal:

 class Point { XType x; YType y; public: Point (const SomePoint& orig) : x(orig.X), y(orig.Y){} Point (const DifferentPoint& orig) : x(orig.x), y(orig.y){} XType getX(){return x;}; YType getY(){return y;}; } 

This is not ideal, but if you cannot access the internal functions of the other two classes, this is a potential solution. Of course, I assumed that your X and Y were at the same time as X and Y ...

Use then

 void printX (const Point& point) { std::cout << point.getX(); } ... SomePoint origin(0,0); printX(Point{origin}); 

The TartanLlama solution above is more flexible, but allows the use of different types of X and Y.

0
source

I personally prefer to inherit publicly from one of the "offenders" and enter a link to a named member. I find this to be less typical and more convenient to use than the adapters and features mentioned in the other answers.

0
source

Source: https://habr.com/ru/post/1240356/


All Articles