2017-03-10 4 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 부 작동하지 않는다 :베이스 반복자 타입과 std::sort 반면

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); 

#else 부분에서 작업을한다. 나는 왜 그런지 이해하지 못한다. 내 실제 사용 사례에서 나는 또한 boost::adaptors::indirectboost::adaptors::filter을 사용하고 있습니다. (정렬을하기 전에 필터링을 수행하거나 적어도 그렇게하려고 시도하고 어떻게 수행되는지보십시오.) 그래서 나는 단순히 변환을 수행하기 전에 words을 람다 프리디 케이트로 정렬하십시오.

+0

부스트 :: 스왑 (* 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'가'bar'에 대한 비 const 참조를 반환 할 수 없다는 것을 의미합니다. 명시적인'std :: string &'이 필요한가? 기본적으로 값으로 반환됩니까? 내 실제 사용 사례에서 다른 이유로 const 문제를 발견했습니다. 내 실제 사용 사례는 반복자의 벡터에 대해 boost :: adapters :: unique을 집합 으로 만들고, 물론 집합의 문자열을 바꿀 수 없으므로'.base()'접근법은 일하지 마라. 이제 iterators의 사본을 sort/unique로 가져옵니다. –

+0

@MattChambers :'sort'도 랜덤 접근 반복자를 필요로하므로'filter' 또는'unique' 뷰와 함께 사용할 수 없다는 사실에주의하십시오. – Jarod42

+0

이것은 사람들이 필요로하는 것 같지 않지만, 매우 희박합니다. http://coliru.stacked-crooked.com/a/31653bbd316a795b – sehe