c++ - 如何交换 mpl::vector 的两个元素?

标签 c++ boost boost-mpl

我正在编写一个模板函数,它应该交换 boost::mpl::vector 的两个元素(类似于 std::swap)。困难的部分是在编译时没有变量的概念。我已经写了一份草稿,但我想知道是否有更好的方法来解决这个问题。

我当前的代码草图从迭代器中提取整数索引,并执行序列类型的拷贝并交换元素。问题是 - 可以做得更好吗:

#include <boost/mpl/distance.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/comparison.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/clear.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/or.hpp>

using boost::mpl::distance;
using boost::mpl::begin;
using boost::mpl::end;
using boost::mpl::next;
using boost::mpl::at;
using boost::mpl::or_;
using boost::mpl::int_;
using boost::mpl::eval_if;
using boost::mpl::greater;
using boost::mpl::equal;
using boost::mpl::clear;
using boost::mpl::push_back;


namespace boost { namespace mpl {

template<template<typename, typename> class T, class A, class B>
struct eval2 {
    typedef typename T<typename A::type, typename B::type>::type type;
};


namespace details {

    template <typename Dest_seq, typename It_end, typename It_first, typename It_second, typename It_idx>
    struct copy_and_swap {
    private:
        typedef typename eval_if< is_same<It_idx, It_first>,
                                  eval2<push_back, Dest_seq, deref<It_second> >,
                                  eval_if<is_same<It_idx, It_second>,
                                          eval2<push_back, Dest_seq, deref<It_first> >,
                                          eval2<push_back, Dest_seq, deref<It_idx> >
                                         >
                                >::type Limit_idx;
        typedef typename next<It_idx>::type it_idx_next;

    public:
        // next step
        typedef typename eval_if <is_same<it_idx_next, It_end>,
                                  New_seq,
                                  copy_and_swap<New_seq, 
                                                It_end, 
                                                It_first, 
                                                It_second, 
                                                it_idx_next>
                                 >::type type;
    };

} // namespace details


template<typename Seq, typename Begin, typename End>
struct swap {
  private:
    typedef typename begin<Seq>::type                it_begin;
    typedef typename end<Seq>::type                  it_end;
    // get an empty container type "compatible" with Seq
    typedef typename clear<Seq>::type        Container_t;
    // border case - swap self
    typedef typename is_same<Begin, End>::type   swap_self;
    // border case - less than 2 elements in sequence
    typedef typename less<size<Seq>, int_<2> >::type    no_swap;

  public:
    // perform the element swapping
    typedef typename eval_if <or_<swap_self, no_swap>,
                              Seq,
                              details::copy_and_swap<Container_t,
                                                     it_end,
                                                     Begin,
                                                     End,
                                                     it_begin >
                             >::type type;
};

} // namespace mpl
} // namespace boost

这个元函数可以像这样使用:

struct value_printer {
    template< typename U > void operator()(U x) {
        std::cout << x << ',';
    }
};



typedef vector_c<int, 1, 2, 3, 6, 5, 4>::type    test_vect;
typedef begin<test_vect>::type    it_beg;
typedef advance<it_beg, int_<2> >::type    it;
typedef advance<it_beg, int_<5> >::type    it_stop;
typedef m_swap<test_vect, it_stop, it>::type    result;
boost::mpl::for_each< result >( value_printer() );

结果是1,2,4,6,5,3,

最佳答案

这是一个只使用 MPL 元函数的解决方案,没有显式递归。这个想法是从复制序列开头和要交换的第一个值之间的所有值开始,插入第二个值,复制中间值,插入第一个值,最后复制结尾。

此方法的一个缺点是迭代器必须形成一个有效范围:Second 不能在 First 之前。我不认为有什么办法可以用这个解决方案来克服这个限制,但这似乎不是一个无法忍受的要求。

代码如下:

// Precondition: [First, Second] is a valid range in Seq
template< typename Seq, typename First, typename Second >
struct swap {
  private:
    typedef typename begin< Seq >::type begin;
    typedef typename end< Seq >::type   end;

    typedef typename clear< Seq >::type empty_container;

    // Insert values from begin to first
    typedef typename
        copy<
            iterator_range< begin, First >,
            back_inserter< empty_container >
        >::type prefix;

    // Insert second value 
    typedef typename
        push_back<
            prefix, typename
            deref< Second >::type
        >:: type prefixSecond;

    // Insert values from first+1 to second
    typedef typename
        copy<
            iterator_range< typename next< First >::type, Second >,
            back_inserter< prefixSecond >
        >::type prefixSecondMiddle;

    // Insert first value
    typedef typename
        push_back<
            prefixSecondMiddle, typename
            deref< First >::type
        >::type prefixSecondMiddleFirst;

    // Insert values from second+1 to end
    typedef typename
        copy<
            iterator_range< typename next< Second >::type, end >,
            back_inserter< prefixSecondMiddleFirst >
        >::type prefixSecondMiddleFirstSuffix;

  public:
    typedef prefixSecondMiddleFirstSuffix type;
};

关于c++ - 如何交换 mpl::vector 的两个元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7930977/

相关文章:

c++ - 使用 Boost.Spirit 解析标记化的自由形式语法

c++ - 使用 boost python 将 python 列表传递给 c++ 扩展

c++ - 神秘的随机数 - 即使在 "srand()"之后也想要相同

c++ - 我怎样才能从字符串中得到一个词

c++ - 从另一个类调用指向成员函数的指针

c++ - 为什么 std::set 是关联容器

c++ - boost shared_ptr : How to use custom deleters and allocators

c++ - boost::mpl::equal 对于 vector 和 vector_c 总是 false

c++ - 默认模板参数中的 MPL 占位符替换

c++ - boost::mpl::map 失败 boost::mpl::equal?