2016-04-01 2 views
8

Ich möchte eine sortierte Ansicht von std::vector<std::chrono::milliseconds>, aber ich möchte nicht den ursprünglichen Container ändern. std::reference_wrapper scheint perfekt dafür und es funktioniert gut für einen Vektor von ganzen Zahlen.Warum kann ich keinen Vektor von reference_wrapper <std :: chrono :: Millisekunden> sortieren?

Ich habe dieses kleine Beispiel erstellt:

#include <chrono> 
#include <vector> 
#include <iostream> 
#include <algorithm> 
#include <functional> 

int main() 
{ 
    std::vector<int> numbers{1, 42, 3, 9, 5}; 
    std::vector<std::reference_wrapper<int>> sorted_numbers(numbers.begin(), numbers.end()); 
    std::sort(sorted_numbers.begin(), sorted_numbers.end()); 

    std::cout << "Numbers: "; 
    for (const auto& n : numbers) 
     std::cout << n << ' '; 
    std::cout << '\n'; 

    std::cout << "Sorted numbers: "; 
    for (const auto& n : sorted_numbers) 
     std::cout << n << ' '; 
    std::cout << '\n'; 

    std::cout << "Numbers: "; 
    for (const auto& n : numbers) 
     std::cout << n << ' '; 
    std::cout << '\n'; 

    std::vector<std::chrono::milliseconds> durations{std::chrono::milliseconds{1}, 
                std::chrono::milliseconds{42}, 
                std::chrono::milliseconds{3}, 
                std::chrono::milliseconds{9}, 
                std::chrono::milliseconds{5}}; 
    std::vector<std::reference_wrapper<std::chrono::milliseconds>> 
     sorted_durations(durations.begin(), durations.end()); 
    // std::sort(sorted_durations.begin(), sorted_durations.end()); 

    std::cout << "Durations: "; 
    for (const auto& d : durations) 
     std::cout << d.count() << ' '; 
    std::cout << '\n'; 

    std::cout << "Sorted durations: "; 
    for (const auto& d : sorted_durations) 
     std::cout << d.get().count() << ' '; 
    std::cout << '\n'; 

    std::cout << "Durations: "; 
    for (const auto& d : durations) 
     std::cout << d.count() << ' '; 
    std::cout << '\n'; 
} 

die die erwartete Ausgabe erzeugt (außer dass sorted_durations ist natürlich nicht sortiert, da diese auf Kommentar wird):

 
Numbers: 1 42 3 9 5 
Sorted numbers: 1 3 5 9 42 
Numbers: 1 42 3 9 5 
Durations: 1 42 3 9 5 
Sorted durations: 1 42 3 9 5 
Durations: 1 42 3 9 5 

Wie Sie kann sehen, der ursprüngliche Vektor der Ganzzahlen numbers ist unverändert durch die Sortieroperation auf sorted_numbers getan - das ist genau das, was ich für die sorted_durations Vektor auch will. Aber wenn ich diese Zeile auszeichne, wird mein Compiler sehr böse mit mir und ich muss zugeben, dass ich nicht herausfinden kann, was es mir zu sagen versucht. Mein Compiler Klirren ist ++ Version 3.8 und ich bauen das Beispielprogramm wie folgt:

clang++ -std=c++11 test.cc

Und hier ist die Fehlerausgabe erhalte ich:

In file included from test.cc:4: 
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/algorithm:62: 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:1935:11: error: invalid operands to binary expression 
     ('std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >' and 'std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >') 
     if (*__i < *__first) 
      ~~~~^~~~~~~~~ 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:5308:12: note: in instantiation of function template specialization 
     'std::__heap_select<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > > 
     >' requested here 
     std::__heap_select(__first, __middle, __last); 
     ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:2310:24: note: in instantiation of function template specialization 
     'std::partial_sort<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > > 
     >' requested here 
       _GLIBCXX_STD_A::partial_sort(__first, __last, __last); 
          ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:5460:9: note: in instantiation of function template specialization 
     'std::__introsort_loop<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > >, 
     long>' requested here 
      std::__introsort_loop(__first, __last, 
      ^
test.cc:35:10: note: in instantiation of function template specialization 'std::sort<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > 
     *, std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > 
     > >' requested here 
    std::sort(sorted_durations.begin(), sorted_durations.end()); 
     ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/chrono:488:7: note: candidate template ignored: could not match 'duration' against 'reference_wrapper' 
     operator<(const duration<_Rep1, _Period1>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/chrono:667:7: note: candidate template ignored: could not match 'time_point' against 'reference_wrapper' 
     operator<(const time_point<_Clock, _Dur1>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_pair.h:220:5: note: candidate template ignored: could not match 'pair' against 'reference_wrapper' 
    operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:297:5: note: candidate template ignored: could not match 'reverse_iterator' against 
     'reference_wrapper' 
    operator<(const reverse_iterator<_Iterator>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:347:5: note: candidate template ignored: could not match 'reverse_iterator' against 
     'reference_wrapper' 
    operator<(const reverse_iterator<_IteratorL>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:1055:5: note: candidate template ignored: could not match 'move_iterator' against 'reference_wrapper' 
    operator<(const move_iterator<_IteratorL>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:1061:5: note: candidate template ignored: could not match 'move_iterator' against 'reference_wrapper' 
    operator<(const move_iterator<_Iterator>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_vector.h:1421:5: note: candidate template ignored: could not match 'vector' against 'reference_wrapper' 
    operator<(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:2569:5: note: candidate template ignored: could not match 'basic_string' against 'reference_wrapper' 
    operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:2581:5: note: candidate template ignored: could not match 'basic_string' against 'reference_wrapper' 
    operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:2593:5: note: candidate template ignored: could not match 'const _CharT *' against 
     'std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >' 
    operator<(const _CharT* __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/array:238:5: note: candidate template ignored: could not match 'array' against 'reference_wrapper' 
    operator<(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b) 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/tuple:824:5: note: candidate template ignored: could not match 'tuple' against 'reference_wrapper' 
    operator<(const tuple<_TElements...>& __t, 
    ^
In file included from test.cc:4: 
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/algorithm:62: 
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:61: 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_heap.h:235:35: error: invalid operands to binary expression ('std::reference_wrapper<std::chrono::duration<long, 
     std::ratio<1, 1000> > >' and 'std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >') 
      if (*(__first + __secondChild) < *(__first + (__secondChild - 1))) 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_heap.h:407:9: note: in instantiation of function template specialization 
     'std::__adjust_heap<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > >, 
     long, std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > >' requested here 
      std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value)); 
      ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:1933:12: note: in instantiation of function template specialization 
     'std::make_heap<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > > 
     >' requested here 
     std::make_heap(__first, __middle); 
     ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:5308:12: note: in instantiation of function template specialization 
     'std::__heap_select<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > > 
     >' requested here 
     std::__heap_select(__first, __middle, __last); 
     ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:2310:24: note: in instantiation of function template specialization 
     'std::partial_sort<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > > 
     >' requested here 
       _GLIBCXX_STD_A::partial_sort(__first, __last, __last); 
          ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_algo.h:5460:9: note: in instantiation of function template specialization 
     'std::__introsort_loop<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > *, 
     std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > >, 
     long>' requested here 
      std::__introsort_loop(__first, __last, 
      ^
test.cc:35:10: note: in instantiation of function template specialization 'std::sort<__gnu_cxx::__normal_iterator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > 
     *, std::vector<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >, std::allocator<std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > > > > 
     > >' requested here 
    std::sort(sorted_durations.begin(), sorted_durations.end()); 
     ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/chrono:488:7: note: candidate template ignored: could not match 'duration' against 'reference_wrapper' 
     operator<(const duration<_Rep1, _Period1>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/chrono:667:7: note: candidate template ignored: could not match 'time_point' against 'reference_wrapper' 
     operator<(const time_point<_Clock, _Dur1>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_pair.h:220:5: note: candidate template ignored: could not match 'pair' against 'reference_wrapper' 
    operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:297:5: note: candidate template ignored: could not match 'reverse_iterator' against 
     'reference_wrapper' 
    operator<(const reverse_iterator<_Iterator>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:347:5: note: candidate template ignored: could not match 'reverse_iterator' against 
     'reference_wrapper' 
    operator<(const reverse_iterator<_IteratorL>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:1055:5: note: candidate template ignored: could not match 'move_iterator' against 'reference_wrapper' 
    operator<(const move_iterator<_IteratorL>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_iterator.h:1061:5: note: candidate template ignored: could not match 'move_iterator' against 'reference_wrapper' 
    operator<(const move_iterator<_Iterator>& __x, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/stl_vector.h:1421:5: note: candidate template ignored: could not match 'vector' against 'reference_wrapper' 
    operator<(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:2569:5: note: candidate template ignored: could not match 'basic_string' against 'reference_wrapper' 
    operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:2581:5: note: candidate template ignored: could not match 'basic_string' against 'reference_wrapper' 
    operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/basic_string.h:2593:5: note: candidate template ignored: could not match 'const _CharT *' against 
     'std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >' 
    operator<(const _CharT* __lhs, 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/array:238:5: note: candidate template ignored: could not match 'array' against 'reference_wrapper' 
    operator<(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b) 
    ^
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/tuple:824:5: note: candidate template ignored: could not match 'tuple' against 'reference_wrapper' 
    operator<(const tuple<_TElements...>& __t, 
    ^

Es geht tatsächlich für ein bisschen länger, aber Stackoverflow wird nicht Lassen Sie mich alle 55000 Zeichen des Fehlers posten.

Kann mir bitte jemand erklären, was ich falsch mache oder warum das einfach nicht möglich ist (wenn das der Fall ist)?

+4

Es scheint, wie std :: reference_wrapper nicht Binäroperators bereitstellt < – Incomputable

+0

auf [Bezugsseite] (http://de.cppreference.com/w/cpp/utility/functional/reference_wrapper) es gibt keine Operatoren zum Vergleich, also denke ich, dass Sie Ihre eigenen schreiben müssen. – Incomputable

+1

Wie viele Elemente enthält der Vektor? Kannst du es nicht einfach kopieren? Das macht man jetzt sowieso mit dem 'reference_wrapper'-Vektor. –

Antwort

14

Der erste Fehler scheint ziemlich klar:

In file included from [...]/algorithm:62: 
[...]/bits/stl_algo.h:1935:11: error: invalid operands to binary expression 
     ('std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >' and 'std::reference_wrapper<std::chrono::duration<long, std::ratio<1, 1000> > >') 
     if (*__i < *__first) 
      ~~~~^~~~~~~~~ 

Sie nicht < verwenden können zwei reference_wrapper<duration<...>> Objekte zu vergleichen.

Die Umstellung auf duration<...> geschieht nicht, weil (wie ein Kommentar oben sagt) die operator< für duration ein Funktions-Template und seine Argumente abgeleitet werden können, nicht aus reference_wrapper<duration<...>>.

Wenn Sie eine Instanz von std::less<std::chrono::milliseconds> an std::sort übergeben haben, würde dies dazu führen, dass die Wrapper in die Durationstypen konvertiert und korrekt verglichen werden.

std::sort(sorted_durations.begin(), sorted_durations.end(), std::less<std::chrono::milliseconds>{}); 

Diese im Grunde sagt, dass Sie die Objekte sortiert werden sollen, indem sie als milliseconds nicht reference_wrapper<milliseconds> zu vergleichen.

+0

Vielen Dank. Ich schätze, die vielen Seiten mit Fehlern haben mich völlig blind gegenüber dieser anfänglichen klaren Nachricht gemacht. Es funktioniert perfekt. –

+1

Beginnen Sie immer mit dem ersten Fehler :-) Bei C++ - Templates kann die Kaskade späterer Fehler Nebeneffekte des ersten Fehlers sein und verschwindet möglicherweise, wenn Sie den ersten Fehler beheben. –

4

Per @ Niall Vorschlag, können Sie einen lambda als Komparator für die sort() verwenden:

std::sort(sorted_durations.begin(), sorted_durations.end(), 
    [](const std::reference_wrapper<std::chrono::milliseconds> &a, 
     const std::reference_wrapper<std::chrono::milliseconds> &b) 
     -> bool { return a.get() < b.get(); }); 
+0

Rechts. Aber in diesem Fall ist 'std :: sort (sorted_durations.begin(), sorted_durations.end(), std :: less ());' wie von @ Jonathan Wakely übernommen, einfacher. –

+1

Einverstanden, es ist einfacher. –

Verwandte Themen