以下のコードを使用すると、最初の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
の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]
コメントを追加