¿Cómo puedo boost :: range :: sort () a boost :: transform_range?

Quiero obtener los elementos únicos de un vector basado en un miembro de foo . Estoy usando boost::adaptors::transform para seleccionar el miembro, luego ordenar y luego usar boost::adaptors::unique . Estoy teniendo problemas para conseguir el paso de orden para trabajar. Dejando de lado la llamada unique por ahora, he probado el siguiente código en Coliru .

 #include  #include  #include  #include  #include  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 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; } 

La sección #if no funciona:

 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 (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, boost::iterators::use_default, boost::iterators::use_default>; _ForwardIterator2 = boost::iterators::transform_iterator<std::__cxx11::basic_string (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, 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 (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, 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 (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, 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 (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, 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 (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, 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 (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, 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 (*)(const foo&), std::vector >]' 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 (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, boost::iterators::use_default, boost::iterators::use_default>, std::__cxx11::basic_string, boost::iterators::random_access_traversal_tag, std::__cxx11::basic_string, long int, false, false>::reference, boost::iterators::detail::iterator_facade_base<boost::iterators::transform_iterator<std::__cxx11::basic_string (*)(const foo&), __gnu_cxx::__normal_iterator<foo*, std::vector >, boost::iterators::use_default, boost::iterators::use_default>, std::__cxx11::basic_string, boost::iterators::random_access_traversal_tag, std::__cxx11::basic_string, long int, false, false>::reference)' swap(*__a, *__b); 

Mientras que std::sort con el tipo de iterador base en la sección #else sí funciona. No entiendo porque En mi caso de uso real, también estoy usando boost::adaptors::indirect and boost::adaptors::filter (y prefiero hacer el filtrado antes de hacer la clasificación, o al menos tratar de hacerlo y ver cómo se realiza), por eso no estoy simplemente clasificando las words con un predicado lambda antes de hacer la transformación.

El problema es que tiene una vista de cadenas temporales que no puede intercambiar. Puedes arreglar tu código con lo siguiente:

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

Manifestación

Tenga en cuenta que con eso, ordena la cadena directamente, y no la clase.