简体   繁体   English

如何在boost :: mpl算法中使用std :: tuple类型?

[英]How to use std::tuple types with boost::mpl algorithms?

The boost::mpl algorithms seem not to be able to work on std::tuple types out of the box, eg, the following does not compile (boost-1.46.0, g++ snapshot 2011-02-19): 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");

What is the easiest way to make the boost::mpl algorithms work on std::tuple ? 使boost::mpl算法在std::tuple上运行的最简单方法是什么?

  • Does evtl. 是evtl. boost::fusion provide this functionality (as it does so for boost::tuple )? boost::fusion提供了这个功能(就像它对boost::tuple )?
  • If not, would it be possible to carry over the fusion implementation for boost::tuple to std::tuple easily? 如果没有,是否可以轻松地将boost::tuple的融合实现转移到std::tuple
  • If not either, do I really have to implement all the intrinsic metafunctions listed in the MPL documentation or which ones would be sufficient? 如果不是,我是否真的必须实现MPL文档中列出的所有内部元函数或哪些足够? (The docs only says " many of intrinsic metafunctions offer a default implementation that will work in majority of cases ", but it is not clear which ones exactly. And some tests with just providing begin and end did not lead me anywhere). (文档只说“ 许多内在元函数提供了一个在大多数情况下都能工作的默认实现 ”,但目前尚不清楚究竟是哪些。而一些只提供开始和结束的测试并没有引导我到任何地方)。

If you wanted to not convert the std::tuple into a mpl type, you can overload the tag dispatching boost mpl uses: 如果你不想将std :: tuple转换为mpl类型,你可以重载标签调度boost 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;
};

} }

And the associated test: 以及相关的测试:

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

}

I tested this with gcc 4.7.2 and clang 3.2. 我用gcc 4.7.2和clang 3.2测试了这个。 It should contain everything you need to use anything in the mpl (actually a litte more than it needs). 它应该包含在mpl中使用任何东西所需的一切(实际上它比它需要的更多)。 You can think of a tuple as a mpl::list (forward iterator compile type). 您可以将元组视为mpl :: list(转发迭代器编译类型)。 So, to make it play nice you should implmenet what boost::mpl::list does. 所以,为了让它发挥得更好你应该实现boost :: mpl :: list的功能。 A quick look into the boost/mpl/list/aux_ directory: begin_end.hpp empty.hpp iterator.hpp pop_front.hpp push_back.hpp size.hpp clear.hpp front.hpp push_front.hpp tag.hpp are the relevant files that need to be implemented. 快速浏览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是需要的相关文件将要执行。

Converting from std::tuple to boost types and back seems to be the easiest way 从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;}

*tested with: *测试用:
boost_1_46_0 and g++-4.5 on MacOSx MacOSx上的boost_1_46_0和g ++ - 4.5
boost_1_45_0 and g++-4.5 on Ubuntu 10.10 Ubuntu 10.10上的boost_1_45_0和g ++ - 4.5

This is my version for converting between std::tuple and boost types, but as said in the comment above, conversion probably is not very compile-time efficient, ie, will result in (unnecessary) long compile times. 这是我在std :: tuple和boost类型之间进行转换的版本,但正如上面的注释所述,转换可能不是非常有效的编译时间,即会导致(不必要的)长编译时间。 A solution that avoids conversion surely would be preferred... 一个避免转换的解决方案肯定是首选......

#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() {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM