2017-01-20 19 views
2

私は今までのすべてのニーズに合った素敵な小さなjack-of-all取引型を持っています。C++のコンストラクタとコールのあいまいさの解決

template <typename T> 
class Array 
{ 
    ... 

public: 
    int Data; // custom value 
    virtual void InitData() { Data = 0; } 

    Array(const Array& array); 
    template <typename U, typename = std::enable_if<std::is_same<U, T>::value, U>> Array(const Array<U>& array); 
    template <typename... Ts> Array(const Ts&... items); 

    void Add(const T& item); 
    template <typename... Ts> void Add(const T& item, const Ts&... rest); 
    void Add(const Array& array); 
} 

template <typename... Ts> Array(const Ts&... items);は私がArray<T> array = { ... }を行い、そして割り当て、{...}初期化子リストを返すことができます。コンストラクタのどれも明示的ではないので、それは信じられないほど便利ですが、私が今立ち往生している理由です。

私はアレイに「合理的」なものを追加したいと考えています。今私の主なユースケースは、次のとおりです。

using Curve = Array<float2>; 

class Poly : public Array<float2> { using Array::Array; void InitData() override { Data = 1; } }; 
class Curve2 : public Array<float2> { using Array::Array; void InitData() override { Data = 2; } }; 
class Curve3 : public Array<float2> { using Array::Array; void InitData() override { Data = 3; } }; 

上記std::is_same<>ものは、特に同じ同じではないとして、すべての曲線扱うことができるようにすることです:静的」異なる程度のカーブタイプを、そしてすべてがうまくあります型付き "なので、DrawCurve(const Curve&)のような関数で行うことは、度合いをチェックしてから適切な処置をとることです。 CurveはArrayの素晴らしいエイリアスであり、Curve2などは度の特殊化です。それは非常にうまく動作します。

私はカーブ構築に入ると、通常、カーブオブジェクトを持っています。これには、のポイントまたはカーブセグメントが追加されます。だから私は行うことができるようにしたい:私は追加呼び出すときの追加は、()がかかりますので

Curve3 curve; 
curve.Add(float2()); // ambiguity 
curve.Add(Array<float2>()); 

は、残念ながら、私は、ここに曖昧さを得るのいずれかfloat2または正常に動作しますArray<float2>、しかし、アレイ暗黙のコンストラクタtemplate <typename... Ts> Array(const Ts&...)があり、これは引数としてfloat2をとることができます。私は

template <typename A, typename = std::enable_if<std::is_same<A, Array>::value, A>> 
void Add(const Array& array); 

のような明示的な配列を取るコンストラクタを作る試みたが、その後、私はなどをするfloat2するCurve3から新しい変換エラーを取得し、それが混乱になり

Array::Add(float2()); // and 
Array::Add(Array<float2>(float2())); 

間ので曖昧さがあります。

私の希望は、テンプレートや他のC++のおいしさのどこかに、私が必要とする簡単な解決策があることです。 (はい、私はちょうどメソッドの名前を変更することができます:: AddItem()と:: AddArray()と問題が2番目に終わるが、私はこれをダブルしたいので、これを望んでいないので+=その後、主にちょうどそれを使用しています。

任意のアイデア?

+0

[ここ](http://coliru.stacked-crooked.com/a/beaea40305a2119f)にコードを差し込めば、それらの2つの間にはあいまいではないようです –

答えて

3

をパラメータパックは、少なくとも一つの項目が含まれており、その項目の型がない場合は、

template <typename... Ts> Array(const Ts&... items); 

のみを使用したいことを確認Arrayテンプレートインスタンス。パラメータパックが空の場合、これはデフォルトのコンストラクタになりますので、このケースを個別に処理してみましょう。必要に応じてデフォルトのコンストラクタを明示的に定義し、必要な処理を行うようにします。今、このユースケースからその可能性を排除し、先を進めることができます。

は邪魔にならない、あなたがここでやりたいことは、それは一つの引数を持っている場合にのみ、このコンストラクタを使用することを得た:

template <typename T1, typename... Ts> Array(const T1 &t1, const Ts&... items); 

あなたが明示的にt1を使用するには、このコンストラクタを変更する必要があります、それが使用する既存のパラメータパックに加えて。それは十分に簡単なはずですが、それでは十分ではありません。まだあいまいです。 T1がArrayでない場合にのみ、このコンストラクタを選択したいとします。

おそらく、畳み込まれたものを考え出し、それを単一のstd::enable_ifに入れて、それをこのテンプレートに押し込む方法があります。その最初のテンプレートパラメータがArray、類似していない場合にのみ、このコンストラクタを選択するために、SFINAEを使用するには、このコンストラクタのテンプレートに簡単なstd::enable_ifを追加し

template<typename T> class is_not_array : public std::true_type {}; 

template<typename T> 
class is_not_array<Array<T>> : public std::false_type {}; 

そして:しかし、明瞭さ、そして簡単にするために、私はヘルパークラスを使用します他のコンストラクターで既にstd::enable_ifをどのように使用しているかを示します。

これはすべてのあいまいさを解決するはずです。このコンストラクタは、このヘルパークラスの助けを借りて、Arrayではない少なくとも1つのテンプレートパラメータでのみ選択されます。 Arrayの場合、このコンストラクタは解決できません。その場合、別のコンストラクタに移動します。

const T &の代わりに、テンプレートで汎用参照を使用することもお勧めします。

+0

ありがとう、それを解決しました!テンプレートのメタプログラミングはまだ私にとって非常に不思議です。 :) – Alex

関連する問題