首页 > 解决方案 > 检查实现了哪些基类

问题描述

我有两个模板类 A 和 B

template <typename T> class A { /* ... */ };
template <typename T> class B { /* ... */ };

现在我想编写一个执行不同操作的函数,具体取决于在传递的参数中实现了哪些基类。

template <typename T>
void foo(const T& object) {
  if ( /* T inherits from some A<S1> */ )
    std::cout << "object has type A";
  if ( /* T inherits from some B<S2> */ )
    std::cout << "object has type B";
}

我想我可以将S1andS2作为模板参数添加到 foo 但是为每个调用手动指定它们是一个很大的麻烦。理论上,如果T已知,编译器应该能够检查它是否继承了任何A<S>.

这可以做到吗?

编辑:

除了 StoryTeller 的解决方案之外,我还使用这段代码来相应地转换我的T-objects:

template<template<typename...> class TT, class T>
struct specialization_base_of {

    template<typename... Args>
    static constexpr TT<Args...>  checkVal(TT<Args...> const&);

    static constexpr void checkVal(...);

    template<typename... Args>
    static constexpr TT<Args...>&  checkRef(TT<Args...> const&);

    static constexpr void checkRef(...);

    template<typename... Args>
    static constexpr TT<Args...> const& checkCref(TT<Args...> const&);

    static constexpr void checkCref(...);

    template<typename... Args>
    static constexpr TT<Args...>*  checkPtr(TT<Args...> const&);

    static constexpr void checkPtr(...);

    using value_type = decltype(checkVal(std::declval<T>()));
    using ref_type = decltype(checkRef(std::declval<T>()));
    using cref_type = decltype(checkCref(std::declval<T>()));
    using ptr_type = decltype(checkPtr(std::declval<T>()));
};

标签: c++templatesinheritance

解决方案


依赖重载解析的好老技巧也应该在这里起作用:

template<template<typename...> class TT, class T>
struct is_specialization_base_of {
    template<typename... Args>
    static constexpr std::true_type  check(TT<Args...> const&);

    static constexpr std::false_type check(...);

    static constexpr bool value = decltype(check(std::declval<T>()))::value;
};

第一个模板参数是模板名称,可以接受任意数量的类型参数。你需要一个,但为什么要限制自己呢?

然后我们定义了两个重载,一个是接受任何假设特化的模板,TT第二个是作为 C 风格变量参数函数的后备。这是整个机器。如果我们调用check任何公开派生自 的假设特化的类,TT则根据重载解析的工作方式选择第一个重载。否则选择后备。

我们的 trait 的值由 的未评估上下文中产生的类型决定,在decltype那里执行重载决议,但由于它是未评估的上下文,因此无需定义任何内容,只需声明即可。decltype因此产生结果类型。

这是一个简单的测试套件

struct C1 : A<int> {};
struct C2 : B<int> {};

struct C3 : A<int>, B<char> {};

static_assert(is_specialization_base_of<A, C1>::value);
static_assert(!is_specialization_base_of<B, C1>::value);

static_assert(!is_specialization_base_of<A, C2>::value);
static_assert(is_specialization_base_of<B, C2>::value);

static_assert(is_specialization_base_of<A, C3>::value);
static_assert(is_specialization_base_of<B, C3>::value);

我将把这个特性插入你的模板函数的练习留给你。我只是建议把那些if' 变成if constexpr一些额外的好东西。


推荐阅读