Проверьте, является ли один набор типов подмножествами с композицией - PullRequest
0 голосов
/ 13 июня 2018

Я должен проверить, если дано два кортежа, один является подмножеством другого.Я нашел это элегантное решение Проверьте, является ли один набор типов подмножеством другого .

Но проблема этого решения заключается в том, что оно не учитывает подтипы, например:

using t1 = std::tuple<int, double>;
using t2 = std::tuple<double, int>;
using t3 = std::tuple<t1, t2>;

Это может не пройти тест подмножества.

#include <tuple>
#include <type_traits>

template <typename T, typename... Ts>
constexpr bool contains = (std::is_same<T, Ts>{} || ...);

template <typename Subset, typename Set>
constexpr bool is_subset_of = false;

template <typename... Ts, typename... Us>
constexpr bool is_subset_of<std::tuple<Ts...>, std::tuple<Us...>>
       = (contains<Ts, Us...> && ...);

Причина в том, что если мы сделаем подмножество в t1 и t3, выражение содержит сравнивает int с t1, что не удается.Таким образом, необходимо изменить функцию для поиска подтипов.

PS Этот код будет работать только на C ++ 17

1 Ответ

0 голосов
/ 13 июня 2018

Вы можете «сплющить» вложенные кортежи, если вас не интересует структура вложенности кортежей.Это может означать

int main() {
  using t1 = std::tuple<int, double>;
  using t2 = std::tuple<double, int>;
  using t3 = std::tuple<t1, t2>;

  static_assert(
    std::is_same<
      flatten<t3>,
      std::tuple<int, double, double, int>
    >{}
  );

  static_assert(false == is_subset_of<t1, t3>);
  static_assert(true == is_subset_of< t1, flatten<t3> >);

  return 0;
}

Быстрая и грязная реализация flatten может выглядеть следующим образом.

namespace detail {

template<class... Ts>
struct flatten {
  static_assert(sizeof...(Ts) == 0, "recursion break (see specializations)");

  template<class... Result>// flattened types are accumulated in this pack
  using type = std::tuple<Result...>;
};

template<template<class...> class Nester, class... Nested, class... Ts>
struct flatten<Nester<Nested...>, Ts...> {// if first arg is nested then unpack
  template<class... Result>
  using type = typename flatten<Nested..., Ts...>::template type<Result...>;
};

template<class T0, class... Ts>
struct flatten<T0, Ts...> {// if `T0` is flat then just append it to `Result...`
  template<class... Result>
  using type = typename flatten<Ts...>::template type<Result..., T0>;
};

};// detail

template<class... Ts>
using flatten = typename detail::flatten<Ts...>::template type<>;
...