SFINAE:检查两个可变包的串联是否与一个包相同

SFINAE: Check whether the concatenation of two variadic packs is the same as one pack

有没有办法检查两个可变参数包的串联是否与第三个可变参数包相同。

template<typename... Args>
struct ClassOne
{
}

template<typename... Args>
struct ClassTwo
{
}

template<typename... Args>
struct ClassThree
{
}

template<typename... PackA, typename... PackB, typename... PackC>
void foo(ClassOne<PackA...>, ClassTwo<PackB...>, ClassThree<PackC...>)
{
}

我希望仅在 PackA... = PackB..., PackC... 时启用 foo

首先,创建一个pack class来存储一堆类型:

template <typename... Ts> struct pack { };

然后,编写一个函数来检查两个包是否相同:

template <typename P0, typename P1>
struct are_packs_same;

template <typename... T0s, typename... T1s>
struct are_packs_same<pack<T0s...>, pack<T1s...>>
    : std::bool_constant<(sizeof...(T0s) == sizeof...(T1s)) 
                      && (std::is_same_v<T0s, T1s> && ...)>
{
};

最后,您需要一个函数来连接两个包:

template <typename P0, typename P1>
struct concat_packs;

template <typename... T0s, typename... T1s>
struct concat_packs<pack<T0s...>, pack<T1s...>>
{
    using type = pack<T0s..., T1s...>;
};

用法示例:

int main()
{
    using p0 = pack<int, char>;
    using p1 = pack<float>;
    using p2 = pack<int, char, float>;

    static_assert(are_packs_same<
        typename concat_packs<p0, p1>::type,
        p2>::value);
}

live wandbox example

相当简单...

template <typename ...>
struct pack{};

template<typename... PackA, typename... PackB, typename... PackC,
  typename = typename std::enable_if
     <std::is_same<pack<PackA...>, 
                   pack<PackB..., PackC...>>::value
     >::type>
void foo(ClassOne<PackA...>, ClassTwo<PackB...>, ClassThree<PackC...>)
{
}
template<class...> struct types{
  friend constexpr std::true_type operator==(types,types) { return {}; }
  template<class...Ts>
  friend constexpr std::false_type operator==(types,types<Ts...>) { return {}; }
  constexpr types(){}
  template<class...Ts>
  friend constexpr auto operator!=(types self, types<Ts...> ts )
  ->std::integral_constant<bool, !decltype(self == ts){}>
  { return{}; }
};
template<class...Ts>constexpr types<Ts...> pack{};

现在:

template<typename... PackA, typename... PackB, typename... PackC>
std::enable_if_t<pack<PackA...> ==pack<PackB...> && pack<PackB...> ==pack<PackC...>>
foo(ClassOne<PackA...>, ClassTwo<PackB...>, ClassThree<PackC...>) { }

读起来像英文。

或者:

template<class...> struct types{
  friend constexpr bool operator==(types,types) { return true; }
  template<class...Ts>
  friend constexpr bool operator==(types,types<Ts...>) { return false; }
  constexpr types(){}
  template<class...Ts>
  friend constexpr bool operator!=(types self, types<Ts...> ts )
  { return !(self==ts); }
};

哪个稍微简单一些,工作原理也差不多。