通常,适配器的目的是以修改的格式进行函数调用。有没有办法为成员变量做同样的事情?也就是说,我有一个包含SomePoint
的对象和另一个包含DifferentPoint
的对象。 SomePoint
将其数据存储为成员变量大写X
和Y
,其中AnotherPoint
将其数据存储为成员变量小写x
和x
。所以问题是你不能写一个接受SomePoint
或DifferentPoint
的函数,因为你无法访问.x
或.X
(甚至使用模板而不是完全专门针对每种不同的点类型,在这种情况下,您可能只是在点类型上重载)。
问题是,当请求.X
时,是否有一种方法可以使适配器为SomePoint
生成.x
?这两种点类型都是库类,因此我无法直接编辑其中任何一个的内部。我还想避免复制数据。
答案 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;};
}
这并不理想,但如果你无法访问其他两个类的内部,那么这是一个潜在的解决方案。当然,我假设您的X
和Y
与x
和y
同时......
然后使用
void printX (const Point& point) {
std::cout << point.getX();
}
...
SomePoint origin(0,0);
printX(Point{origin});
上面的TartanLlama解决方案更灵活,允许各种类型的X和Y.
答案 3 :(得分:0)
我个人更愿意从其中一名罪犯那里公开继承“&#39;并引入对不同命名成员的引用。我相信与其他答案中提到的适配器和特性相比,它的打字更少,使用更方便。