Как использовать типы std :: tuple с алгоритмами boost :: mpl? - PullRequest
6 голосов
/ 24 февраля 2011

Алгоритмы boost::mpl не могут работать с std::tuple типами "из коробки", например, следующее не компилируется (boost-1.46.0, g ++ snapshot 2011-02-19):

#include <tuple>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>

namespace mpl=boost::mpl;

typedef mpl::vector<int,float,bool> types;
static_assert(mpl::contains<types, float>::value, "vector contains bool");

typedef std::tuple<int,float,bool> types2;
// the following does not compile:
// error: no class template named ‘apply’ in ‘struct boost::mpl::contains_impl<boost::mpl::non_sequence_tag>’
static_assert(mpl::contains<types2, float>::value, "tuple contains bool");

Какой самый простой способ заставить алгоритмы boost::mpl работать на std::tuple?

  • Есть ли евтл. boost::fusion предоставить эту функциональность (как это происходит для boost::tuple)?
  • Если нет, можно ли перенести реализацию слияния для boost::tuple на std::tuple легко?
  • Если нет, действительно ли мне нужно реализовать все внутренние метафункции, перечисленные в документации MPL , или каких из них будет достаточно? (В документации сказано только: « многие встроенные метафункции предлагают реализацию по умолчанию, которая будет работать в большинстве случаев », но неясно, какие именно. И некоторые тесты с предоставлением только начала и конца не привели меня куда угодно).

Ответы [ 3 ]

7 голосов
/ 07 апреля 2013

Если вы не хотите преобразовывать std :: tuple в тип mpl, вы можете перегрузить использование тегов, которое mpl использует для повышения:

#include <tuple>
#include <boost/mpl/sequence_tag.hpp>
#include <boost/mpl/pop_front_fwd.hpp>
#include <boost/mpl/push_front_fwd.hpp>
#include <boost/mpl/push_back_fwd.hpp>
#include <boost/mpl/front_fwd.hpp>
#include <boost/mpl/empty_fwd.hpp>
#include <boost/mpl/size_fwd.hpp>
#include <boost/mpl/at_fwd.hpp>
#include <boost/mpl/back_fwd.hpp>
#include <boost/mpl/clear_fwd.hpp>
#include <boost/mpl/pop_back_fwd.hpp>
#include <boost/mpl/iterator_tags.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/begin_end_fwd.hpp>


namespace boost { namespace mpl {
  namespace aux { struct std_tuple; }

  template<class ... Args>
  struct sequence_tag<std::tuple<Args...> >
  {
    typedef aux::std_tuple type;
  };

  template<>
  struct front_impl< aux::std_tuple >
  {
    template< typename Tuple > struct apply
        : std::tuple_element<0, Tuple>
    {
    };
  };

  template<>
  struct empty_impl< aux::std_tuple >
  {
      template< typename Tuple > struct apply
          : std::integral_constant<bool, std::tuple_size<Tuple>::value == 0>
      {
      };
  };

  template<>
  struct pop_front_impl< aux::std_tuple >
  {
    template< typename Tuple > struct apply;

    template< class First, class ... Types > struct apply<std::tuple<First, Types...>>
    {
      typedef std::tuple<Types...> type;
    };
  };

  template<>
  struct push_front_impl< aux::std_tuple >
  {
    template< typename Tuple, typename T > struct apply;

    template< typename T, typename ... Args >
    struct apply<std::tuple<Args...>, T>
    {
        typedef std::tuple<T, Args...> type;
    };
  };

  template<>
  struct push_back_impl< aux::std_tuple >
  {
    template< typename Tuple, typename T > struct apply;

    template< typename T, typename ... Args  >
    struct apply<std::tuple<Args...>, T>
    {
      typedef std::tuple<Args..., T> type;
    };
  };


  template<>
  struct size_impl< aux::std_tuple >
  {
    template< typename Tuple > struct apply
        : std::tuple_size<Tuple>
    {
    };
  };

  template<>
  struct at_impl< aux::std_tuple >
  {
    template< typename Tuple, typename N > struct apply
        : std::tuple_element<N::value, Tuple>
    {
    };
  };

  template<>
  struct back_impl< aux::std_tuple >
  {
    template< typename Tuple > struct apply
        : std::tuple_element<std::tuple_size<Tuple>::value - 1, Tuple>
    {
    };
  };

  template<>
  struct clear_impl< aux::std_tuple >
  {
    template< typename Tuple > struct apply
    {
      typedef std::tuple<> type;
    };
  };

  template<>
  struct pop_back_impl< aux::std_tuple >
  {
    template<int ...> struct tuple_seq {};
    template<int N, int ...S> struct tuple_gens : tuple_gens<N-1, N-1, S...> {};
    template<int ...S> struct tuple_gens<0, S...>{ typedef tuple_seq<S...> type; };

    template < class Tuple, class Index> struct apply_impl;
    template < class Tuple, int ... S> struct apply_impl<Tuple, tuple_seq<S...>>
    {
      typedef std::tuple<typename std::tuple_element<S, Tuple>::type...> type;
    };

    template< typename Tuple > struct apply : apply_impl<Tuple, typename tuple_gens<std::tuple_size<Tuple>::value - 1>::type> { };
  };

template< class ... Args >
struct tuple_iter;

  template< class ... Args >
  struct tuple_iter<std::tuple<Args...>>
  {
    typedef aux::std_tuple tag;
    typedef forward_iterator_tag category;
  };

template<>
struct begin_impl< aux::std_tuple >
{
  template< class Tuple > struct apply
  {
    typedef tuple_iter<Tuple> type;
  };
};

template<>
struct end_impl< aux::std_tuple >
{
  template< typename > struct apply
  {
    typedef tuple_iter<std::tuple<>> type;
  };
};

template< typename First, class ... Args >
struct deref< tuple_iter<std::tuple<First, Args...> > >
{
  typedef First type;
};

template< typename First, class ... Args >
struct next< tuple_iter<std::tuple<First, Args...>> >
{
  typedef tuple_iter< std::tuple<Args...> > type;
};

} }

И соответствующий тест:

#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/back.hpp>
#include <boost/mpl/clear.hpp>
#include <boost/mpl/pop_back.hpp>
#include <boost/mpl/contains.hpp>


#include <boost/mpl/aux_/test.hpp>
MPL_TEST_CASE()
{
  typedef std::tuple<int, char, bool> Tuple;
  MPL_ASSERT((is_same<front<Tuple>::type, int>));
  MPL_ASSERT_RELATION( size<Tuple>::type::value, ==, 3 );
  MPL_ASSERT(( is_same< pop_front<Tuple>::type, std::tuple<char, bool> > ));
  MPL_ASSERT(( is_same< push_front<Tuple, unsigned>::type, std::tuple<unsigned, int, char, bool> > ));
  MPL_ASSERT(( is_same< push_back<Tuple, unsigned>::type, std::tuple<int, char, bool, unsigned> > ));
  MPL_ASSERT_RELATION( empty<Tuple>::type::value, ==, false );
  MPL_ASSERT(( is_same< at_c<Tuple, 0>::type, int > ));
  MPL_ASSERT(( is_same< at_c<Tuple, 1>::type, char > ));
  MPL_ASSERT(( is_same< back<Tuple>::type, bool > ));
  MPL_ASSERT(( is_same< clear<Tuple>::type, std::tuple<> > ));
  MPL_ASSERT(( is_same< pop_back<Tuple>::type, std::tuple<int, char> > ));
  MPL_ASSERT(( contains<Tuple, int> ));
  MPL_ASSERT(( contains<Tuple, char> ));
  MPL_ASSERT(( contains<Tuple, bool> ));
  MPL_ASSERT_NOT(( contains<Tuple, unsigned> ));

}

Я проверял это с gcc 4.7.2 и clang 3.2. Он должен содержать все, что вам нужно, чтобы использовать что-либо в mpl (на самом деле, немного больше, чем нужно). Вы можете думать о кортеже как о mpl :: list (тип компиляции прямого итератора). Итак, чтобы все было хорошо, вы должны понять, что делает boost :: mpl :: list. Быстрый просмотр каталога boost / mpl / list / aux_: begin_end.hpp empty.hpp iterator.hpp pop_front.hpp push_back.hpp size.hpp clear.hpp front.hpp push_front.hpp tag.hpp соответствующие файлы, которые необходимо реализовать.

3 голосов
/ 25 февраля 2011

Преобразование из std :: tuple в типы Boost и обратно, кажется, самый простой способ

#include <iostream>
#include <tuple>
#include <type_traits>
#include <boost/mpl/if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/vector.hpp>

namespace mpl = boost::mpl;

template<typename Sequence, typename T>
struct push_front;

template<template<typename...> class Sequence, typename T, typename ... Args>
struct push_front< Sequence<Args...>,T> {
  typedef Sequence<T, Args...> type;
};

template<template<typename...> class To, typename From> struct tuple_change;

template<template<typename...> class To, template<typename...> class From, typename ... Args>
struct tuple_change<To, From<Args...>>
{
  typedef To<Args...> type;
};

template<typename Sequence, size_t N>
struct at : std::tuple_element<N,Sequence> { };

template<typename Sequence>
struct empty;

template<template<typename...> class Sequence, typename ... Args>
struct empty<Sequence<Args...>> {
  typedef Sequence<> type;
};

template<
  size_t N,
  typename Sequence,
  template<typename> class Pred,
  typename ... Args >
struct while_impl
{
  typedef typename mpl::if_c<
    Pred<
        typename at<Sequence, sizeof...(Args) - N -1>::type
    >::value,
    typename push_front<
        typename while_impl<N-1, Sequence, Pred, Args...>::type, 
            typename at<Sequence,sizeof...(Args)-N-1>::type
    >::type,
    typename empty< Sequence > ::type
  >::type type;
};

template<
  typename Sequence,
  template<typename> class Pred,
  typename ... Args >
struct while_impl<-1, Sequence, Pred, Args...>
: empty<Sequence> {
};


template<
  typename Sequence,
  template<typename> class Pred>
struct while_;

template<
  template<typename...> class Sequence,
  template<typename> class Pred,
  typename ... Args >
struct while_< Sequence<Args...>, Pred >
{
  typedef typename while_impl<sizeof...(Args)-1, Sequence<Args...>, Pred, Args...>::type type;
};

template<typename T>
struct not_na : mpl::not_< std::is_same<mpl_::na, T> >
{ };

template<template<typename...> class To, typename From>
struct to_boost;

template<template<typename...> class To, typename...Args >
struct to_boost<To, std::tuple<Args...> > :
  tuple_change< mpl::vector, std::tuple<Args...> >
{ };

template< typename From >
struct to_std;

template<template<typename...> class From, typename...Args >
struct to_std< From<Args...> > :
   while_<typename tuple_change< std::tuple, From<Args...> >::type, not_na>
{ };

static_assert(
std::is_same<
    mpl::vector< char, int, bool>,
    typename to_boost<mpl::vector, std::tuple<char, int, bool> >::type
  >::value,
"tuple_change to boost failed");

static_assert(
  std::is_same<
    std::tuple< char, int, bool>,
    typename to_std< mpl::vector<char, int, bool> >::type
  >::value,
"tuple_change from boost failed");

int main(){ return 0;}

* проверено с:
boost_1_46_0 и g ++ - 4.5 на MacOSx
boost_1_45_0 и g ++ - 4.5 в Ubuntu 10.10

2 голосов
/ 28 февраля 2011

Это моя версия для преобразования между типами std :: tuple и boost, но, как сказано в комментарии выше, преобразование, вероятно, не очень эффективно во время компиляции, то есть приведет к (ненужному) длительному времени компиляции. Решение, которое избегает преобразования, безусловно, было бы предпочтительным ...

#include <tuple>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>

namespace mpl=boost::mpl;

//_ 1. vector_size and vector_at for std::tuple and mpl sequences
template <typename SEQ> struct vector_size 
: mpl::size<SEQ>
{};

template <typename... TYPES> struct vector_size<std::tuple<TYPES...>> 
: std::tuple_size<std::tuple<TYPES...>>
{};

template <typename SEQ, size_t N> struct vector_at 
: mpl::at_c<SEQ, N>
{};

template <typename... TYPES, size_t N> struct vector_at<std::tuple<TYPES...>, N> 
: std::tuple_element<N, std::tuple<TYPES...>>
{};

//_ 2. convert
template <template <typename...> class COLLECT,
      typename SEQ, size_t N, typename... ARGS>
struct convert_helper 
  : convert_helper<COLLECT, SEQ, N-1, typename vector_at<SEQ, N-1>::type, ARGS...>
{};

template <template <typename...> class COLLECT, typename SEQ, typename... ARGS>
struct convert_helper<COLLECT, SEQ, 0, ARGS...> {
  typedef COLLECT<ARGS...> type;
};

template <template <typename...> class COLLECT, typename SEQ>
struct convert 
  : convert_helper<COLLECT, SEQ, vector_size<SEQ>::value>
{};

//_ 3. tests
typedef std::tuple<int, float, bool> types;
typedef mpl::vector<int, float, bool> types_v;

static_assert(std::is_same<convert<std::tuple, types_v>::type, types>::value, "boost2std works");
static_assert(std::is_same<convert<mpl::vector,types>::type, types_v>::value, "std2boost works");

int main() {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...