比较可变模板

Comparing variadic templates

本文关键字:比较      更新时间:2023-10-16

如果我有两个可变模板参数,AB,我如何在编译时确保A的所有成员的类型也是B的子集的类型(以相同的顺序)?

的例子:

template<typename...A>
struct Foo {
  template<typename...B>
  static void bar()
  {
  }
}
...
Foo<Apple, Orange>:: template bar<Apple, Orange, Grape>(); // this compiles
Foo<Apple, Orange>:: template bar<Orange, Grape>(); // this doesn't

对于一般子集,我不知道,但如果您可以保证BA..., More...的形式,那么这可能会做:

#include <functional>
#include <tuple>
template <typename ...A>
struct var_equal : std::false_type { };
template <typename A1, typename ...Aother, typename B1, typename ...Bother>
struct var_equal<std::tuple<A1, Aother...>, std::tuple<B1, Bother...>>
{
  static const bool value = std::is_same<A1, B1>::value && var_equal<std::tuple<Aother...>, std::tuple<Bother...>>::value;
};
template <typename ...B>
struct var_equal<std::tuple<>, std::tuple<B...>> : std::true_type { };

template<typename...A>
struct Foo {
  template<typename...B>
  static void bar()
  {
    static_assert(var_equal<std::tuple<A...>, std::tuple<B...>>::value, "Hello");
  }
};

(对不起,var_equal是个糟糕的名字。它应该叫一个更合适的名字,比如initial_equal)


更新:这是一般的解决方案,由Luc Danton详细制定(见这里他的漂亮风格的代码):

#include <type_traits>
#include <tuple>
template <typename Sub, typename Super>
struct subset_of : std::false_type {};
template<typename Same, typename... AOther, typename... BOther>
struct subset_of<std::tuple<Same, AOther...>, std::tuple<Same, BOther...>>
: subset_of<
    std::tuple<AOther...>
    , std::tuple<BOther...>
> {};
template<typename ADifferent, typename BDifferent, typename... AOther, typename... BOther>
struct subset_of<std::tuple<ADifferent, AOther...>, std::tuple<BDifferent, BOther...>>
: subset_of<
    std::tuple<ADifferent, AOther...>
    , std::tuple<BOther...>
> {};
template<typename... B>
struct subset_of<std::tuple<>, std::tuple<B...>>: std::true_type {};
template<typename... A>
struct Foo {
    template<typename... B>
    static void bar()
    {
        static_assert(subset_of<std::tuple<A...>, std::tuple<B...>>::value, "Hello");
    }
};
测试用例:

struct Apple{}; struct Orange{}; struct Grape{};
int main()
{
    Foo<Apple, Orange>::bar<Apple, Orange, Grape>();               // this compiles
    Foo<Apple, Orange>::bar<Grape, Apple, Grape, Orange, Grape>(); // this also compiles
    Foo<Apple, Orange>::bar<Orange, Grape>();                      // this doesn't
}