"适配器"对于成员变量

时间:2016-01-11 15:30:21

标签: c++ adapter

通常,适配器的目的是以修改的格式进行函数调用。有没有办法为成员变量做同样的事情?也就是说,我有一个包含SomePoint的对象和另一个包含DifferentPoint的对象。 SomePoint将其数据存储为成员变量大写XY,其中AnotherPoint将其数据存储为成员变量小写xx。所以问题是你不能写一个接受SomePointDifferentPoint的函数,因为你无法访问.x.X(甚至使用模板而不是完全专门针对每种不同的点类型,在这种情况下,您可能只是在点类型上重载)。

问题是,当请求.X时,是否有一种方法可以使适配器为SomePoint生成.x?这两种点类型都是库类,因此我无法直接编辑其中任何一个的内部。我还想避免复制数据。

4 个答案:

答案 0 :(得分:9)

通常的做法是编写一个traits类来指定如何获取所需的数据。

这是使用指向成员的可能实现。如果您愿意,可以将它们变成函数或lambdas。

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;
};

然后你会像这样使用它:

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

答案 1 :(得分:1)

在TartanLlama所说的基础上,您可以使用类似于std::tuple的免费函数及其获取&lt;&gt;。

#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;
}

答案 2 :(得分:0)

编写适配器类Point,它具有两种目标类型的隐式转换语法。 注意它要求复制数据,因此不理想:

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;};
}

这并不理想,但如果你无法访问其他两个类的内部,那么这是一个潜在的解决方案。当然,我假设您的XYxy同时......

然后使用

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

上面的TartanLlama解决方案更灵活,允许各种类型的X和Y.

答案 3 :(得分:0)

我个人更愿意从其中一名罪犯那里公开继承“&#39;并引入对不同命名成员的引用。我相信与其他答案中提到的适配器和特性相比,它的打字更少,使用更方便。