2016-01-11 15 views
5

通常、アダプタの目的は、変更された形式で関数呼び出しを行うことです。メンバー変数に同じようなことをする方法はありますか?つまり、SomePointを含むオブジェクトと、DifferentPointを含む別のオブジェクトがあるとします。 SomePointは、メンバー変数としてデータを格納します。XおよびYここで、AnotherPointは、メンバー変数としてデータを小文字のxおよびxとして保存します。だから問題があるのは、SomePointまたはDifferentPointのいずれかを受け入れる関数を書くことができないということです。.xまたは.Xにアクセスすることはできません(テンプレートを使用して、それぞれの異なるポイントタイプに完全に特化しない場合でも可能です。ポイントタイプのオーバーロード)。メンバ変数の "アダプタ"

.xが要求されたときにSomePointのために.Xを生成するアダプタを作成する方法はありますか?どちらのポイントタイプもライブラリクラスなので、どちらかの内部構造を直接編集することはできません。私はまた、データのコピーを避けたいと思います。

+0

メンバー関数 'getx()'と 'getX()'を扱う場合、この問題が根本的にどのように違うのか混乱します。 –

+0

@ChristianHackl次に、アダプタの関数の実装を変更して、正しい値を返します(Pointクラスごとに1つのアダプタを持つことができます)。 –

+0

メンバー変数にそのようなアダプタ関数を書くのはどうですか? 'int getX(SomePoint const&)'や 'int getX(differentPoint const&)'のようなものです。 –

答えて

9

これを行う通常の方法は、目的のデータを取り出す方法を指定するtraitsクラスを作成することです。

ここでは、ポインタへのポインタを使用した実装が考えられます。あなたはむしろそれらを機能またはラムダにすることができます。

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

+1

これは、すべてのデータもコピーします。私は質問に言及しなかった(私は編集する)が、私はすべてのデータをコピーしないようにしたい。 –

+0

申し訳ありません。この要件が私の答えで満たされていないことを示すために、一番上に少し注意します。 – Dennis

0

個人的には、「犯罪者」の1人から一般に継承され、別のメンバーに参照されることをお勧めします。私は他の答えで言及されているアダプターと形質の両方よりも使用するのがよりタイピングとコンビニエンスが少ないと信じています。

+0

既に作成されたクラス(ライブラリクラスなど)を使用している場合は、これはオプションではありません。 –

+1

@EdwinRodríguez、なぜですか?私はそれに問題はないと思う。 – SergeyA

+0

申し訳ありませんが、私はあなたが言ったことを誤解しました –

1

TartanLlamaによると、std::tupleのような無料の機能を使用して、<>を取得できます。

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