如何检测类型是否是泛型类型列表之一

bra*_*ing 6 c++ enable-if template-meta-programming c++11

如果我有

template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;
Run Code Online (Sandbox Code Playgroud)

如果某个候选类型X是其中之一,那么最紧凑的测试方法是什么?我正在寻找类似的东西

boost::enable_if< is_instantiation_of_any<X,A,B,C,D> >
Run Code Online (Sandbox Code Playgroud)

但是 A、B、C 和 D 是模板,所以我不确定如何构建上述内容。

for*_*818 8

不确定是否存在 a std::is_instantiation_of,但如果所有模板都具有相同数量的参数,则实现它很简单(如果不存在则更复杂)。要检查类型是否是任何给定模板的实例化,您只需要折叠它(需要 C++17):

#include<iostream>
#include<type_traits>


template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;


template <typename T,template<typename> typename X>
struct is_instantiation_of : std::false_type {};

template <typename A,template<typename> typename X>
struct is_instantiation_of<X<A>,X> : std::true_type {};

template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
    static const bool value = ( ... || is_instantiation_of<T,X>::value);
};

int main(){
    std::cout << is_instantiation_of< A<int>, A>::value;
    std::cout << is_instantiation_of< A<double>, B>::value;
    std::cout << is_instantiation_of_any< A<int>,A,B>::value;
}
Run Code Online (Sandbox Code Playgroud)

输出

101
Run Code Online (Sandbox Code Playgroud)

要获得符合 C++11 的解决方案,我们可以使用Jarod42s 答案之一中的巧妙技巧:

template <bool ... Bs>
using meta_bool_and = std::is_same<std::integer_sequence<bool, true, Bs...>,
                                   std::integer_sequence<bool, Bs..., true>>;
Run Code Online (Sandbox Code Playgroud)

它的相当聪明的,true,a,b,c并且a,b,c,true只在同一时候abc都是truestd::integer_sequence是 C++14,但我们在这里只需要一个将 bool 作为其定义的一部分的类型:

namespace my {
    template <typename T,T ...t>
    struct integer_sequence {};
}
Run Code Online (Sandbox Code Playgroud)

使用它,我们可以将上面的内容重写为:

template <bool ... Bs>
using my_all = std::is_same<my::integer_sequence<bool, true, Bs...>,
                            my::integer_sequence<bool, Bs..., true>>;
Run Code Online (Sandbox Code Playgroud)

而作为"ANY(a,b,c,d,...)"仅仅是"! ALL( !a, !b, !c, !d,...)"我们可以使用:

template <bool ... Bs>
struct my_any { static constexpr bool value = ! my_all< ! Bs...>::value; };
Run Code Online (Sandbox Code Playgroud)

is_instantiation_of_anyC++11 友好的方式编写:

template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
    static const bool value = my_any< is_instantiation_of<T,X>::value ...>::value;
};
Run Code Online (Sandbox Code Playgroud)

完整的 C++11 示例

  • 这些模板问题也总是狙击我 https://xkcd.com/356/ (4认同)
  • 标记为 C++11,因此应替换折叠表达式。(`all_of`有一个[技巧](/sf/answers/2600408471/)来避免递归,`any_of`只是`none_of`的否定(这是带有否定条件的`all_of` ))。 (3认同)
  • @bradgonesurfing 不确定 Ayxans 的评论有多严重,问题是“任意数量的混合类型和非类型参数”不仅仅是比我在答案中提出的复杂 x2 或 x3,而是一个完全不同的故事。 (2认同)