2016-11-16 13 views
1

コンストラクタテンプレートを条件付きで有効にしようとしています。完全なC++ 11準拠のコンパイラでは、余分なデフォルトのテンプレート引数を使用してこれを行う方法を知っています。しかし、私はVS2012をサポートする必要があります。これはstd :: enable_ifを持ちますが、デフォルトの関数テンプレート引数はサポートしていません。 C++ 11ではenable_ifとVS2012のコンストラクタ

、私は次のように記述します。

template<typename T> 
struct Class 
{ 
    template<typename O, 
      typename = typename std::enable_if<std::is_convertible<O*, T*>::value>::type> 
    Class(O*) {} 
}; 

私は次のことを試してみましたが、それはエラーC4336と様々なフォローアップのエラーを与える:

template<typename T> 
struct Class 
{ 
    template <typename O> 
    Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type *= nullptr) 
    { 
    } 
}; 

がありますVS2012でこの作業を行う方法はありますか?

追加

次のようにクラスの使用法は次のようになります。

struct X { }; 
struct X2 : X { }; 
struct Y { }; 

struct Client 
{ 
    Client(Class<X> x) {} 
    Client(Class<Y> y) {} 
}; 

void test() { 
    X2* x2; 
    Client client(x2); // error C2668: ambiguous call to overloaded function 
        // (without std::enable_if) 
} 
+0

クラスに別のコンストラクタがあるのですか、それとも唯一のコンストラクタですか? – skypjack

+0

実際のクラスには、他のコンストラクタもあります。 – user2019765

答えて

0

あなたはですので、解決に近いです!

template<typename T> 
struct Class 
{ 
    template <typename O> 
    Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type * = nullptr) 
    { 
    } 
}; 

違いを見つけましたか?パラメータリスト内の*=は、multiplication/assignment operatorとして解析され、ポインタ型とそれに続くデフォルトの引数として解析されませんでした。したがって、構文エラー。

これは、トークンを構成するときにできるだけ多くの文字を消費するようにC++パーサーが指定されているためです(いわゆる最大マッチルール)。スペースを追加すると、それを2つの別々のトークンに分割します。

+0

ああ...あなたが言うように、それは本当に近いし、遡及的には愚かな間違いだった。 – user2019765

0

私は怖いです、あなたはヘルパー構築物の機能を使用する必要があると思います(私は見つけられませんでしたそれを周りに)。しかし、このような何かが動作するはずです:

#include <type_traits> 

template<typename T> 
struct Class 
{ 
    template<typename O> 
    Class(O* o) { construct(o, std::integral_constant<bool, std::is_convertible<T*, O*>::value>()); } 

    template<class O> 
    void construct(O*, std::true_type) { /* convertible */ } 
    template<class O> 
    void construct(O*, ...) { /* not convertible */ } 
}; 

struct X { }; 
struct Y : public X { }; 

void check() { 
    X x; 
    int i; 
    Class<Y> cl(&x); 
    Class<Y> cl1(&i); 
} 
+0

これは面白いアイデアです...しかし、元の問題は、クラスがスマートなポインタテンプレートであり、別のクラスの2つのコンストラクタを呼び出すときにあいまいな変換があり、この解決策では解決されない可能性があります。たぶん、私はその状況の最小限のバージョンを提供することができます。 – user2019765

0

C++ 11ので、あなたもそれを行うために委任コンストラクタを使用することができます。

template<typename T> 
class Class { 
    template<typename O> 
    Class(O *o, std::true_type) {} 

    template<typename O> 
    Class(O *o, std::false_type) {} 

public: 
    template<typename O> 
    Class(O *o): Class(o, typename std::is_convertible<O*, T*>::type) {} 
}; 

基本的な考え方は、、多分派遣タグの一つでありますVS2012でもうまく動作します。
詳細はhereを参照してください。

+0

提案していただきありがとうございますが、残念ながら委任コンストラクタもVS2012ではサポートされていません。 – user2019765