2017-03-10 87 views
1

我想根據foo的成員獲得vector<foo>中的獨特元素。我使用boost::adaptors::transform來選擇成員,然後排序,然後使用boost::adaptors::unique。我無法讓排序步驟起作用。撇開unique現在呼籲,我已經嘗試Coliru下面的代碼。如何提升:: range :: sort()boost :: transformed_range?

#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進行排序。

+0

'boost :: swap(* asString.begin(),* asString.begin());'失敗。 – Jarod42

+0

你不能。排序需要隨機訪問。 – sehe

+0

@sehe transform()文檔聲明它返回的是相同的範圍類型,因此它應該是隨機訪問,對吧? –

回答

2

問題是您有臨時字符串的視圖,您不能交換。你可能會解決你的代碼與以下:

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

Demo

注意,對於這一點,你串直接進行排序,而不是類。

+0

啊,這是有道理的'const foo&x'不能返回一個非const引用'bar'。顯式的'std :: string&'必要嗎?它會默認返回值?在我的真實用例中,我發現了常見問題的原因不同。我真正的用例是使'boost :: adapters :: unique'在一個迭代器向量上工作到一個集合,當然這個集合中的字符串不能交換,所以'.base()'方法可以沒有工作。現在我拿一個迭代器的副本sort/unique。 –

+0

@MattChambers:'sort'同樣需要隨機訪問器迭代器,所以不能與'filter'或'unique'視圖一起使用。 – Jarod42

+0

這很漂亮,但不太可能成爲人們所需要的,IYAM:http://coliru.stacked-crooked.com/a/31653bbd316a795b – sehe