SFINAE: check if combining two variation packages with one package

Is there a way to check if the concatenation of two packets of variational arguments coincides with the third packet of variational arguments.

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...>)
{
}

I would like foo to turn on only if PackA ... = PackB ..., PackC ...

+4
source share
3 answers

Rather simple ...

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...>)
{
}
+4
source

First, create a class packto hold several types:

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

Then write a function to check if the two packages match:

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> && ...)>
{
};

Finally, you need a function to combine the two packages:

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...>;
};

Usage example:

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

+1
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{};

Now:

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...>) { }

which reads like english.

As an alternative:

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); }
};

It is a bit simpler and works similarly.

+1
source

Source: https://habr.com/ru/post/1684941/


All Articles