如何交换 mpl::vector 的两个元素?
我正在编写一个模板函数,它应该交换 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,
I'm writing a template function which should swap two elements of a boost::mpl::vector
(similarly to std::swap
). The difficult part is there is no concept of a variable during compile time. I have written a draft but I wonder if there are better ways to approach this.
My current code sketch extracts an integral index from iterators and performs a copy of the sequence type with the elements swapped. The question is - can this be done better:
#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
This metafunction can be used like:
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() );
and the result is 1,2,4,6,5,3,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是一个仅使用 MPL 元函数的解决方案,没有显式递归。这个想法是首先复制序列开头和第一个要交换的值之间的所有值,插入第二个值,复制中间,插入第一个值,最后复制末尾。
此方法的缺点是迭代器必须形成有效范围:
Second
不能在First
之前。我认为这个解决方案没有任何方法可以克服这个限制,但这似乎并不是一个难以忍受的要求。这是代码:
Here is a solution using only MPL metafunctions, without explicit recursion. The idea is to start by copying all the values between the beginning of the sequence and the first value to swap, insert the second value, copy the middle, insert the first value, and finally copy the end.
A disadvantage of this method is that the iterators must form a valid range:
Second
must not be beforeFirst
. I don't think there is any way to overcome this restriction with this solution, but it does not seem like an unbearable requirement.Here is the code: