使用下面的代码,我收到编译器投诉,称前两个模板之间对 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
的基础,编译器可以使用两个版本的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();
关于c++ - 如何使用 is_base_of 专门化模板而不与主模板混淆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42178235/