c++ - subconjuntos - union de conjuntos




Compruebe si un conjunto de tipos es un subconjunto del otro (6)

¿Cómo se puede verificar si un paquete de parámetros (interpretado como un conjunto) es un subconjunto de otro?

Hasta ahora solo tengo el marco (usando std :: tuple), pero ninguna funcionalidad.

#include <tuple>
#include <type_traits>

template <typename, typename>
struct is_subset_of : std::false_type
{
};

template <typename ... Types1, typename ... Types2>
struct is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>>
    : std::true_type
{
    // Should only be true_type if Types1 is a subset of Types2
};

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

    static_assert(is_subset_of<t1, t1>::value, "err");
    static_assert(is_subset_of<t1, t2>::value, "err");
    static_assert(is_subset_of<t2, t1>::value, "err");
    static_assert(is_subset_of<t2, t3>::value, "err");
    static_assert(!is_subset_of<t3, t2>::value, "err");
}

No se permite que cada tipo ocurra más de una vez en un conjunto.

Sería bueno si la solución funciona con C ++ 11.


Aquí hay una respuesta de C ++ 17 que creo que es bastante más simple que la respuesta de Piotr :

template <class T, class... U>
struct contains : std::disjunction<std::is_same<T, U>...>{};

template <typename...>
struct is_subset_of : std::false_type{};

template <typename... Types1, typename ... Types2>
struct is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>> : std::conjunction<contains<Types1, Types2...>...> {};

Demo

disjunction y conjunction son nuevos rasgos de tipo introducidos en C ++ 17. Podemos aprovechar estos para verificar si al menos un tipo en la segunda tupla coincide con "el siguiente tipo" en la primera tupla, para lo cual usamos la expansión del paquete de parámetros ampliamente.


No es exactamente lo que pidió, pero ... solo por diversión, utilizando std::is_base_of puede crear (en C ++ 14, al menos) una función constexpr que funcione como su estructura.

El siguiente es un ejemplo de trabajo (solo C ++ 14)

#include <tuple>
#include <iostream>
#include <type_traits>

template <typename ... Ts>
struct foo : std::tuple<Ts>...
 { };

template <typename ... Ts1, typename ... Ts2>
bool isSubsetOf (std::tuple<Ts1...> const &, std::tuple<Ts2...> const &)
 {
   bool ret { true };

   using un = int[];
   using d2 = foo<Ts2...>;

   (void)un { (ret &= std::is_base_of<std::tuple<Ts1>, d2>::value, 0)... };

   return ret;
 }


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

    std::cout << isSubsetOf(t1{}, t1{}) << std::endl;  // print 1
    std::cout << isSubsetOf(t1{}, t2{}) << std::endl;  // print 1
    std::cout << isSubsetOf(t2{}, t1{}) << std::endl;  // print 1
    std::cout << isSubsetOf(t1{}, t3{}) << std::endl;  // print 1
    std::cout << isSubsetOf(t3{}, t1{}) << std::endl;  // print 0
 }

Si puede usar las funciones de C ++ 17, ¡recomiendo usar la solución de Piotr Skotnicki !

Tuve que implementar esta funcionalidad hace un tiempo. Solo voy a copiar y pegar el código que se me ocurrió en ese momento.

¡No estoy diciendo que esta sea la mejor forma o la más elegante de implementar este tipo de verificación! No me molesté demasiado en pensar en los casos extremos; Es posible que necesite adaptar el código para que se ajuste a sus necesidades.

Para aclarar: ContainsTypes<Lhs, Rhs> comprueba si Rhs es un subconjunto de Lhs .

  template <typename Tuple, typename T>
  struct ContainsType;

  template <typename T, typename U, typename... Ts>
  struct ContainsType<std::tuple<T, Ts...>, U>
  {
      static const bool VALUE = ContainsType<std::tuple<Ts...>, U>::VALUE;
  };

  template <typename T, typename... Ts>
  struct ContainsType<std::tuple<T, Ts...>, T>
  {
      static const bool VALUE = true;
  };

  template <typename T>
  struct ContainsType<std::tuple<>, T>
  {
      static const bool VALUE = false;
  };

  // -----

  template <typename Lhs, typename Rhs>
  struct ContainsTypes;

  template <typename Tuple, typename T, typename... Ts>
  struct ContainsTypes<Tuple, std::tuple<T, Ts...>>
  {
      static const bool VALUE = ContainsType<Tuple, T>::VALUE && ContainsTypes<Tuple, std::tuple<Ts...>>::VALUE;
  };

  template <typename Tuple>
  struct ContainsTypes<Tuple, std::tuple<>>
  {
      static const bool VALUE = true;
  };

Supongo que voy a tirar mi sombrero en el ring. Esta es una solución de C ++ 11 como la solicitada por OP, me doy cuenta de que C ++ 17 tiene características mucho mejores. Es una solución de tipo único (no static const bool explícita, true_type ni similar, solo true_type y false_type , que tienen su propio bool interno)

El inconveniente es que esta solución me obligó a implementar logical_or y logical_and , que obtendríamos conjunction en forma de conjunction y disjunction ).

Milagrosamente, el código es un poco más corto que la solución de Maartan Barnelis , aunque posiblemente sea menos legible

namespace detail
{
template<class T, class U>
struct logical_or : std::true_type{};

template<>
struct logical_or<std::false_type, std::false_type> : std::false_type{};

template<class...>
struct logical_and : std::false_type{};

template<>
struct logical_and<std::true_type, std::true_type> : std::true_type{};
}

template<class...>
struct contains : std::false_type{};

template<class T>
struct contains<T, T> : std::true_type{};

template<class Type, class Types2Head, class... Types2>
struct contains<Type, Types2Head, Types2...> : detail::logical_or<typename std::is_same<Type, Types2Head>::type, typename contains<Type, Types2...>::type>{};

template<class...>
struct is_subset_of : std::false_type{};

template<class Type1, class... Types2>
struct is_subset_of<std::tuple<Type1>, std::tuple<Types2...>> : contains<Type1, Types2...>{};

template<class Type1Head, class... Types1, class... Types2>
struct is_subset_of<std::tuple<Type1Head, Types1...>, std::tuple<Types2...>> : detail::logical_and<typename contains<Type1Head, Types2...>::type, typename is_subset_of<std::tuple<Types1...>, std::tuple<Types2...>>::type>{};

Demo


is_subset_of versión de una respuesta de tu pregunta anterior:

#include <tuple>
#include <type_traits>

template <class T>
struct tag { };

template <class... Ts>
struct is_subset_of_helper: tag<Ts>... { };

template <class, class, class = void>
struct is_subset_of: std::false_type { };

template <bool...>
struct bool_pack { };

template <bool... Bs>
using my_and = std::is_same<bool_pack<Bs..., true>, bool_pack<true, Bs...>>;

template <class... Ts1, class... Ts2>
struct is_subset_of<std::tuple<Ts1...>, std::tuple<Ts2...>, typename std::enable_if< my_and< std::is_base_of<tag<Ts1>, is_subset_of_helper<Ts2...>>::value...  >::value  >::type  >:
   std::true_type { };

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

    static_assert(is_subset_of<t1, t1>::value, "err");
    static_assert(is_subset_of<t1, t2>::value, "err");
    static_assert(is_subset_of<t2, t1>::value, "err");
    static_assert(is_subset_of<t2, t3>::value, "err");
    static_assert(!is_subset_of<t3, t2>::value, "err");
}

[demo en vivo]


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

DEMO







template-meta-programming