我正在编写一个模板函数,它应该交换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,
答案 0 :(得分:1)
这是一个仅使用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;
};