使用基类模板检测 is_base_of

bas*_*eln 3 c++ templates c++14

鉴于代码:

template<typename T, typename Other = SomeDefault>
struct Cat { ... };

template<typename T>
struct Bengal : Cat<T> { ... };

template<typename T>
struct Persian : Cat<T, Something> { ... };

struct Siberian : Cat<int> { ... };
Run Code Online (Sandbox Code Playgroud)

我如何实现一个特征,is_cat<T>以便

  • is_cat<Cat<int, float>>is_cat<Bengal<double>>is_cat<Persian<std::string>>is_cat<Siberian>std::true_type
  • is_cat<double> (以及其他不相关的类型)是 std::false_type

我认为std::is_base_of是正确的方向,但我不知道如何使其与基础的未知类型参数一起工作。

Bar*_*rry 5

std::is_base_of在这里没有帮助,它只检查具体的基类是否是基类。但我们不是在寻找一个具体的基础,我们正在寻找一个基类模板。为此,我们可以利用重载解析:

std::false_type is_cat_impl(...);
template <typename T, typename U>
std::true_type is_cat_impl(Cat<T,U>*);

template <typename T>
using is_cat = decltype(is_cat_impl(std::declval<T*>()));
Run Code Online (Sandbox Code Playgroud)

对于一些这是一个Cat<T,U>Cat<T,U>*是一个更好的比赛比...其他任何东西,它不是在所有的比赛。


如果您还想 match Siberian const&,那么,正如 Oliv 所建议的那样,最好使用引用而不是指针:

std::false_type is_cat_impl(...);
template <typename T, typename U>
std::true_type is_cat_impl(Cat<T,U> const volatile&);

template <typename T>
using is_cat = decltype(is_cat_impl(std::declval<T&>()));
Run Code Online (Sandbox Code Playgroud)

  • @basteln 你可以用引用做同样的事情: ... `true_type is_cat_impl(const volatile Cat&lt;T,U&gt;&amp;)` 和 `decltype(is_cat_impl(std::declval&lt;T&amp;&gt;()));` 会更少对 cv ref 资格很敏感。 (3认同)