プライマリテンプレートをあいまいにすることなく、is_base_ofを使用してテンプレートを特殊化するにはどうすればよいですか?

グレン

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

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
max66

Tベースである場合、不明なケースを非アクティブ化する必要がありますA

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

それ以外の場合、TがのベースであるA場合、コンパイラはの2つのバージョンを使用get_code()でき、正しいバージョンを選択できません(あいまいな呼び出し)

以下は完全に機能する例です

#include <iostream>
#include <type_traits>

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

enum Code { UNKNOWN, ACLASS, DCLASS };

template <typename T>
typename std::enable_if<!std::is_base_of<A, T>::value, Code>::type
get_code()
 { std::cout << "code U" << std::endl; return Code::UNKNOWN; }

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

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

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

ただし、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
 }

別の方法はstd::is_base_of、ヘルパー関数のテンプレートパラメーターとしての値を渡すことです。

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

-編集-

別の可能な解決策。

関数がstaticテンプレートclass(またはstruct)のメソッドであることを受け入れることができ、それを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()Sは、誰かが何かを呼び出すソリューションを回避できることを避けるために追加されます

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

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ