2017-09-21 4 views
2

'CoordinateSystem'パラメータで厳密に型指定された3D 'Coordinate'クラスを定義しようとしています。強力な型の座標系を提供するためのテンプレートメタプログラミングの使用

class CoordinateBase { 
    protected: 
     double a, b, c; 

     /* millions of constructors */ 
} 

class System1 : protected CoordinateBase { 
    public: 
     double& X() {return a;} 
     double& Y() {return b;} 
     double& Z() {return c;} 

    protected: 
     /* millions of constructors */ 
} 


class System2 : protected CoordinateBase { 
    public: 
     double& Lat() {return a;} 
     double& Lon() {return b;} 
     double& Alt() {return c;} 

    protected: 
     /* millions of constructors */ 
} 

template<typename T> 
class Coordinate : public T { 
    public: 
     /* millions of constructors */ 
} 

これは動作しますが、私は、ツリー内の各レベルで関与定型の量に満足していないよ(引数なし/明示的な値/コピー/移動:私が使用している現在のメカニズムの簡易版コンストラクタ、代入演算子)。異なるシステムの座標軸に異なる名前を付けることができるようにしたいと思います。

CRTPのようなものを使用すると便利です。実際の座標値をCoordinateクラスに格納し、静的多態性を使用してSystem1とSystem2から取得するメンバーを持つことができます。残念ながら、私はこれを行うことはできません:

少なくとも、私はいくつかの構文が不足している可能性があります、少なくとも、コンパイラはできません。

私は座標内のすべての有効/無効のロジックを入れていたと考えるもう一つの可能​​性:

template<typename T> 
class Coordinate { 
    public: 
     std::enable_if<std::is_same<T, System1>::value, double&> X() {return a;} 

    private: 
     double a; 
} 

しかし、それはかなり速いという醜い取得するために行くと、このクラスの罪のないユーザーに表示されるすべての不快なテンプレートの機械を入れていますがそれ。

私はこの種のものに最適なアプローチが何であるか分かりません。私が望むインターフェースを維持しながら、定型的なコンストラクタ/代入演算子を非常に多く定義する必要を避けるにはどうすればよいですか?

+2

オフトピック:あなたはBoost.Geometryを見たことがありますか?彼らはそこで幾分似たような目標を達成しようとします。 – lisyarus

+0

ちょうど見ていた。私たちの問題空間は、点を使って幾何学的計算をするよりも、座標空間(Boost.Geometryにないいくつかのものを含む)異なる焦点は私が思うように非常に異なる設計目標につながっています –

答えて

2
template<typename T> 
class Coordinate : public T<Coordinate<T>> 

上記のコードは、有効なC++ではありませんTはタイプですが、使用している、それはtemplateだったかのようですので。また、これはCRTPではありません - ここに適切なCRTPの例です:

template <typename T> 
struct base 
{ 
    auto& as_derived()    { return static_cast<T&>(*this); } 
    const auto& as_derived() const { return static_cast<const T&>(*this); } 
}; 

struct derived : base<derived> 
{ 
    // ... 
}; 

あなたはこの方法でCTRPを使用して試みることができる:

このような問題を解決することになった
template <typename T> 
struct base 
{ 
    auto& as_derived()    { return static_cast<T&>(*this); } 
    const auto& as_derived() const { return static_cast<const T&>(*this); } 

    double _x, _y, _z; 

    base(double x, double y, double z) : _x{x}, _y{y}, _z{z} { } 
    base(double v) : _x{v}, _y{v}, _z{v} { } 
}; 

struct coord : private base<coord> 
{ 
public: 
    using base<coord>::base; 

    auto& x() { return this->_x; } 
    auto& y() { return this->_y; } 
    auto& z() { return this->_z; } 
}; 

struct geocoord : private base<geocoord> 
{ 
public: 
    using base<geocoord>::base; 

    auto& lat() { return this->_x; } 
    auto& lon() { return this->_y; } 
    auto& alt() { return this->_z; } 
}; 

int main() 
{ 
    coord c0{1,2,3}; 
    geocoord c1{1}; 

    c0.x() = 10; 
    c1.alt() = 22; 
} 

live example on wandbox

+0

私はあなたがそのように '使用する 'ことができるとは気づきませんでした。それはおそらく私が欠けている部分です。 –

0

template<typename T> 
class CoordinateBase { 
    protected: 
     Coordinate<T>* upcast() {return static_cast<Coordinate<T>*>(this);} 
     const Coordinate<T>* upcast() const {return static_cast<const Coordinate<T>*>(this);} 
}; 

class System1 : private CoordinateBase<System1> { 
    double& X() {return upcast()->c1;} 
    // other coordinates etc. 
}; 

template<typename T> 
class Coordinate : public T { 
    public: 
     /* Constructors */ 

    private: 
     double c1; 
     double c2; 
     double c3; 

    friend class System1; 
}; 

typedef Coordinate<System1> System1Coordinate; 

so sorta-CRTPですが、私はstatic_castを作るために大会に頼っています<>テンプレートパラメータと規約の代わりに安全です。私はCoordinateBaseとSystem1が一般に公開されていないことを意味するいくつかの名前空間やものを省略しました。このアプローチの

利点:

  • システムクラスの座標は、単に座標系の動作を有する特異すべてのコンストラクタは、上部層、そうする必要性に住んで
  • (大部分の座標を取得する)ことができ定義またはusingそれらを下にダウン
  • 私はすべての座標(またはいくつかの重要なサブセット)のために何かを定義することができ、階層の最上位に位置する単一のクラスがあります、算術演算のよう
  • Relativel安全です。私は、CoordinateがCoordinateBaseから派生したものを渡したことをstatic_assertすることができます。自分の名前空間内のすべてのシステムを「内部」のような名前に保つことができ、人々はそれらを使用することを奨励されます。コンパイルされない 'friend'宣言を追加するのを忘れた場合は、自分自身でインスタンス化する必要があります。また、適切な座標名でのみ座標にアクセスできます。
  • わかりやすい。

短所:CoordinateBaseではstatic_castが大会以外で、安全であることを確実にする

  • ない現実的な方法。
  • フレンドの宣言
関連する問題