Могу ли я сортировать вектор кортежа ссылок?

при следующем коде:

std::vector<std::tuple<int&>> v;
int a = 5; v.emplace_back(a);
int b = 4; v.emplace_back(b);
int c = 3; v.emplace_back(c);
int d = 2; v.emplace_back(d);
int e = 1; v.emplace_back(e);
std::sort(std::begin(v), std::end(v));

компилируется с GCC/libstdc++ vs Clang / libc++ binary дает разные результаты.

на gcc / libstdc++ один элемент копируется во все остальные ссылки.

5 4 3 2 1 
5 5 5 5 5

сначала я подумал, что clang / libc++ поведение как и ожидалось но он работает только до 5 элементов в векторе (есть специальный чехол для небольших емкостей).

5 4 3 2 1 
1 2 3 4 5 

когда передача большего количества элементов результат аналогичен gcc.

5 4 3 2 1 0 
3 4 5 5 5 5

так это действительно использовать std::sort для контейнера кортежей со ссылками (т. е. заключил с std::tie, сортировка подмножества структуры)? Если нет, следует ли ожидать каких-либо предупреждений?

1 ответов


так это действительно использовать std::sort для контейнера кортежей со ссылками (т. е. заключил с std::tie, сортировка подмножества структуры)? Если нет, следует ли ожидать каких-либо предупреждений?

нет, и нет. Одно из требований типа на std::sort() это:

  • тип разыменован RandomIt должны соответствовать требованиям MoveAssignable и MoveConstructible.

здесь MoveAssignable требуется в выражении t = rv:

значение t is эквивалентно стоимостью rv до назначения.

но std::tuple<int&> не является MoveAssignable, потому что int& не является MoveAssignable. Если у вас просто есть:

int& ra = a;
int& rb = b;

ra = std::move(rb);

значение ra не эквивалентно предыдущему значению rb. ra еще относится to a, он не изменяется, чтобы ссылаться на b - на самом деле изменилось значение a.

так как наш тип не соответствует условию std::sort() результат std::sort() вызовы-это просто неопределенное поведение.


обратите внимание, что вы мог бы сортировать std::vector<std::tuple<std::reference_wrapper<int>>>, потому что std::reference_wrapper является MoveAssignable.

обратите внимание также, что это напоминает невозможность сортировки контейнера auto_ptr, за старую траву Саттер статьи.