【问题标题】:How do I boost::range::sort() a boost::transformed_range?如何提升::range::sort() 一个 boost::transformed_range?
【发布时间】:2017-08-01 08:29:53
【问题描述】:

我想根据foo 的成员从vector<foo> 中获取唯一元素。我使用boost::adaptors::transform 选择成员,然后排序,然后使用boost::adaptors::unique。我无法让排序步骤正常工作。暂且不谈unique 调用,我已经在Coliru 上尝试了以下代码。

#include <iostream>
#include <string>
#include <vector>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/sort.hpp>

struct foo
{
    foo(std::string a) : bar(a) {}

    std::string bar;
    bool operator<(const foo& rhs) const {return bar < rhs.bar;}
};

int main()
{
    std::vector<foo> words = { foo("z"), foo("d"), foo("b"), foo("c") };

    #if 1
    {
        auto asString = boost::adaptors::transform(words, +[](const foo& x) {return x.bar;});
        auto sortedStrings = boost::range::sort(asString);
        for (const auto& el : sortedStrings)
            std::cout << el << std::endl;
    }
    #else
    {
        auto asString = boost::adaptors::transform(words, +[](const foo& x) {return x.bar;});
        std::sort(asString.begin().base(), asString.end().base());
        for (const auto& el : asString)
            std::cout << el << std::endl;
    }

    {
        auto sortedStrings = boost::range::sort(words);
        for (const auto& el : sortedStrings)
            std::cout << el.bar << std::endl;
    }
    #endif


    return 0;
}

#if 部分不起作用:

In file included from /usr/local/include/c++/6.3.0/bits/char_traits.h:39:0,
                 from /usr/local/include/c++/6.3.0/ios:40,
                 from /usr/local/include/c++/6.3.0/ostream:38,
                 from /usr/local/include/c++/6.3.0/iostream:39,
                 from main.cpp:1:
/usr/local/include/c++/6.3.0/bits/stl_algobase.h: In instantiation of 'void std::iter_swap(_ForwardIterator1, _ForwardIterator2) [with _ForwardIterator1 = boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>; _ForwardIterator2 = boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>]':
/usr/local/include/c++/6.3.0/bits/stl_algo.h:84:20:   required from 'void std::__move_median_to_first(_Iterator, _Iterator, _Iterator, _Iterator, _Compare) [with _Iterator = boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>; _Compare = __gnu_cxx::__ops::_Iter_less_iter]'
/usr/local/include/c++/6.3.0/bits/stl_algo.h:1918:34:   required from '_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>; _Compare = __gnu_cxx::__ops::_Iter_less_iter]'
/usr/local/include/c++/6.3.0/bits/stl_algo.h:1950:38:   required from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>; _Size = long int; _Compare = __gnu_cxx::__ops::_Iter_less_iter]'
/usr/local/include/c++/6.3.0/bits/stl_algo.h:1965:25:   required from 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>; _Compare = __gnu_cxx::__ops::_Iter_less_iter]'
/usr/local/include/c++/6.3.0/bits/stl_algo.h:4707:18:   required from 'void std::sort(_RAIter, _RAIter) [with _RAIter = boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>]'
/usr/local/include/boost/range/algorithm/sort.hpp:33:14:   required from 'RandomAccessRange& boost::range::sort(RandomAccessRange&) [with RandomAccessRange = boost::range_detail::transformed_range<std::__cxx11::basic_string<char> (*)(const foo&), std::vector<foo> >]'
main.cpp:27:57:   required from here
/usr/local/include/c++/6.3.0/bits/stl_algobase.h:148:11: error: no matching function for call to 'swap(boost::iterators::detail::iterator_facade_base<boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>, std::__cxx11::basic_string<char>, boost::iterators::random_access_traversal_tag, std::__cxx11::basic_string<char>, long int, false, false>::reference, boost::iterators::detail::iterator_facade_base<boost::iterators::transform_iterator<std::__cxx11::basic_string<char> (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector<foo> >, boost::iterators::use_default, boost::iterators::use_default>, std::__cxx11::basic_string<char>, boost::iterators::random_access_traversal_tag, std::__cxx11::basic_string<char>, long int, false, false>::reference)'
       swap(*__a, *__b);

std::sort#else 部分中的基本迭代器类型确实有效。我不明白为什么。在我的实际用例中,我还使用了boost::adaptors::indirectboost::adaptors::filter(我更愿意在进行排序之前进行过滤,或者至少尝试这样做并看看它是如何执行的),所以这就是为什么我在进行转换之前,不只是使用 lambda 谓词对 words 进行排序。

【问题讨论】:

  • boost::swap(*asString.begin(), *asString.begin()); 失败。
  • 你不能。排序需要随机访问。
  • @sehe transform() 文档声称它返回的范围类型与其接收的范围类型相同,所以它应该是随机访问,对吧?

标签: c++ boost boost-range


【解决方案1】:

问题是您可以查看无法交换的临时字符串。您可以使用以下代码修复您的代码:

auto asString = boost::adaptors::transform(words, +[](foo& x) -> std::string& {return x.bar;});

Demo

请注意,您直接对字符串进行排序,而不是对类进行排序。

【讨论】:

  • 啊,const foo&amp; x 不能返回对bar 的非常量引用是有道理的。明确的std::string&amp; 是必要的吗?它会默认按值返回吗?在我的真实用例中,我出于不同的原因发现了 const 问题。我真正的用例是让boost::adaptors::unique 将迭代器向量工作到一个集合 中,当然集合中的字符串不能交换,所以.base() 方法不起作用。现在我将迭代器的副本排序/唯一。
  • @MattChambers:注意sort 也需要随机访问器迭代器,因此不能与filterunique 视图一起使用。
  • 这很漂亮,但不太可能是人们需要的,IYAM:coliru.stacked-crooked.com/a/31653bbd316a795b
  • 我必须先sort,然后我的unique 才能完成它的工作;我发现很难。 :) 但是,我之前误读了过滤器文档;当给定一个随机访问范围时,它将返回一个双向范围。所以我会做变换->排序->过滤->唯一。
  • 你用你花哨的通用 lambdas 取笑我。我现在正在使用 VS2013。 :P 令人恼火的是,它也不以理智的方式支持 + 前缀。
猜你喜欢
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
  • 2021-07-11
  • 2021-01-26
  • 2018-12-25
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
相关资源
最近更新 更多