2017-02-11 3 views
2

以下のコードを使用して、最初の2つのテンプレート間でget_codeの呼び出しが曖昧であるというコンパイラーの苦情を受け取ります。特殊なフォームを提供しながら、ベースクラスを検出するコードを作成するにはどうすればよいですか?たとえば、後でclass C : A {}があり、これもACLASSを返す必要があります。どのようにして、is_base_ofを使用してテンプレートを特化できますか?プライマリテンプレートとあいまいではありませんか?

あなたが TAのベースであるとき、コンパイラは get_code()の2つのバージョンを使用することができますし、選択することはできません、 Tがそうでなければ A

template <typename T> 
typename std::enable_if< ! std::is_base_of<A, T>::value, Code>::type 
get_code() // -----------^ 
{ return Code::UNKNOWN; } 

のベースであるとき、未知の場合を無効にする必要があり

class A {}; 
class B : A {}; 
class D {}; 

enum Code { UNKNOWN, ACLASS, DCLASS }; 

template <typename T> 
Code get_code() { return Code::UNKNOWN; } 

template <typename T> 
typename std::enable_if<std::is_base_of<A, T>::value, Code>::type 
get_code() { return Code::ACLASS; } 

template <> 
inline Code get_code<D>() { return Code::DCLASS; } 

Code test1 = get_code<D>(); // OK, chooses DCLASS 
Code test2 = get_code<B>(); // ambiguous call to overloaded function 
+0

のようなものを呼び出すソリューションである回避できることを避けるために追加された[この](http://melpon.org/wandbox/permlink/N3MCPAclgAfI63J4)何探しています? – skypjack

+0

はい、これも良い解決策のように見えます! – Glenn

答えて

3

右1(不明瞭コール)

次は完全な作業例

です

しかし、私はあることヘルパー関数

のためのテンプレートパラメータとして std::is_base_ofの値を渡すことができSFINAE

#include <iostream> 
#include <type_traits> 

class A {}; 
class B : A {}; 
class C {}; 
class D {}; 

enum Code { UNKNOWN, ACLASS, DCLASS }; 

Code gc2h (std::true_type const &) 
{ std::cout << "code A" << std::endl; return Code::ACLASS; } 

Code gc2h (std::false_type const &) 
{ std::cout << "code U" << std::endl; return Code::UNKNOWN; } 

template <typename T> 
Code gc2() 
{ return gc2h(typename std::is_base_of<A, T>::type {}); } 

template <> 
Code gc2<D>() 
{ std::cout << "code D" << std::endl; return Code::DCLASS; } 

int main() 
{ 
    gc2<A>(); // print A 
    gc2<B>(); // print A 
    gc2<C>(); // print U 
    gc2<D>(); // print D 
} 

別の方法を使用せずに同じ結果を得るために、タグのディスパッチをもとに、あなたに別の方法を提案します

#include <iostream> 
#include <type_traits> 

class A {}; 
class B : A {}; 
class C {}; 
class D {}; 

enum Code { UNKNOWN, ACLASS, DCLASS }; 

template <bool> 
Code gc3h(); 

template <> 
Code gc3h<true>() 
{ std::cout << "code A" << std::endl; return Code::ACLASS; } 

template <> 
Code gc3h<false>() 
{ std::cout << "code U" << std::endl; return Code::UNKNOWN; } 

template <typename T> 
Code gc3() 
{ return gc3h<std::is_base_of<A, T>::value>(); } 

template <> 
Code gc3<D>() 
{ std::cout << "code D" << std::endl; return Code::DCLASS; } 

int main() 
{ 
    gc3<A>(); // print A 
    gc3<B>(); // print A 
    gc3<C>(); // print U 
    gc3<D>(); // print D 
} 

- EDIT -

もう一つの可能​​な解決策。あなたの関数はテンプレートclass(またはstruct)のstatic方法であり、あなたが受け入れることができる場合には、部分的な特殊化に基づいて、gc4<T>::func()代わりのgc4<T>()、別の方法として呼ばれていることを受け入れることができる場合

、次の。

#include <iostream> 
#include <type_traits> 

class A {}; 
class B : A {}; 
class C {}; 
class D {}; 

enum Code { UNKNOWN, ACLASS, DCLASS }; 

template <typename T, bool = std::is_base_of<A, T>::value> 
struct gc4; 

template <typename T> 
struct gc4<T, true> 
{ 
    static_assert(true == std::is_base_of<A, T>::value, "!"); 

    static Code func() 
    { std::cout << "code A" << std::endl; return Code::ACLASS; } 
}; 

template <typename T> 
struct gc4<T, false> 
{ 
    static_assert(false == std::is_base_of<A, T>::value, "!!"); 

    static Code func() 
    { std::cout << "code U" << std::endl; return Code::UNKNOWN; } 
}; 

template <> 
struct gc4<D> 
{ 
    static Code func() 
    { std::cout << "code D" << std::endl; return Code::DCLASS; } 
}; 

int main() 
{ 
    gc4<A>::func(); // print A 
    gc4<B>::func(); // print A 
    gc4<C>::func(); // print U 
    gc4<D>::func(); // print D 
} 

static_assert()のは、誰かが

gc4<A, false>::func(); 
+0

優秀な回答!私は詳細なコードサンプルと複数の作業オプションを持っていただければ幸いです。 – Glenn

+0

@Glenn - Skypjackによって提案されたリンクも見てください:2つの機能に基づいて、std :: enable_ifを介して有効になっている別のタイプのソリューションを見てください。最初の機能が有効なときに2番目の機能を削除する必要はありません。 – max66

+0

@Glenn - 複数の作業オプションがありがとうので、別のオプションを追加しました。 – max66

関連する問題