我正在尝试概括一个函数,该函数曾经将两个迭代器带到特定数据结构的向量,然后使用std::iter_swap
以某种方式重新排列元素(例如{{1} })。
由于此函数实际上仅需要数据的一个子集,以后我将需要在其他上下文中使用它,因此我考虑删除对数据结构的依赖,并在此时使用std::sort
调用以处理转换。
很不幸,boost::transform_iterator
似乎对此更改不满意。我可以想象为什么:boost::transform_iterator
通常实现为std::iter_swap
,而取消引用std::swap(*lhs, *rhs)
并不能产生原始元素,不能以正确的方式进行交换。
我想知道是否有办法处理这种情况。我愿意使用transform_iterator
或实验性boost::range
ts(如果需要)。
这个问题可能与this one类似,但是即使解决方案最终还是修改了算法所需的数据子集,而不是外部结构。
这是MWE:
std::ranges
答案 0 :(得分:2)
您可以访问transform_iterator
的{{3}}属性(从iterator_adaptor
公开继承)来实现自定义transform_iter_swap
,以交换包装的迭代器的基础数据。 / p>
例如:
template<class IteratorAdaptor>
void transform_iter_swap(IteratorAdaptor a, IteratorAdaptor b)
{
std::swap(*a.base(), *b.base());
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
transform_iter_swap(begin++, --end);
}
}
之后,您的示例(省略std::vector
部分)将按预期运行:
my_invert(begin, end); // OK
my_print(begin, end); // 3 5 7 9
如果您希望通用功能模板同时涵盖boost(适配器)迭代器和典型迭代器,则可以例如根据迭代器公共if constexpr
typedef
是否从iterator_category
派生而使用boost::iterators::no_traversal_tag
(C ++ 17):
// expand includes with
#include <boost/iterator/iterator_categories.hpp>
template <class It>
void iter_swap(It a, It b) {
if constexpr(std::is_base_of<
boost::iterators::no_traversal_tag,
typename It::iterator_category>::value) {
std::swap(*a.base(), *b.base());
}
else {
std::swap(*a, *b);
}
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
iter_swap(begin++, --end);
}
}
答案 1 :(得分:1)
问题来自您通过的一元谓词。请注意,由于您允许推导返回类型,因此将推导类型推导为int,将返回一个副本,并且当您尝试交换两个不可修改的int时,编译将失败。但是,如果将返回类型指定为int&,则像这样:
auto unwrap = [](A & a)->int& { return a.x; }; // explicitly demand to return ref
它将编译并反转元素。在gcc 8.1.0和clang 6.0.0上进行了测试。