std :: vector <bool>:: ссылка с std :: exchange - PullRequest
0 голосов
/ 07 ноября 2018

Есть ли техническая причина, по которой std :: exchange не работает на std :: vector :: reference или это ошибка в реализации GCC и Clang? С MSVC он прекрасно компилируется .

У меня есть такая настройка (минимальный пример)

struct Manager
{
  std::vector<bool> lifeTimes;

  //Should return the state before trying to kill it
  bool kill(std::size_t index)
  {
    return std::exchange(lifeTimes[index], false);
  }
};

std :: exchange сделал бы это действительно хорошим вкладышем, но GCC жалуется на:

ошибка: невозможно привязать неконстантную ссылку lvalue типа ‘std :: _ Bit_reference & ’к значению типа ‘std :: vector :: reference’ {aka ‘std :: _ Bit_reference’}

Похоже, он жалуется на false , так как только второй параметр - это значение

1 Ответ

0 голосов
/ 07 ноября 2018

Это не ошибка, MSVC компилирует ваш код, потому что имеет расширение, которое позволяет привязывать временный объект (Rvalue) к неконстантной ссылке Lvalue.

Ниже код компилируется с MSVC:

void foo(int& i) {}
foo(20); // you are passing Rvalue and it is bound to Lvalue reference

Выше код не компилируется под G ++ или CLang, когда вы добавляете const, чтобы сделать ссылку на const Lvalue, это работает:

void foo(const int&){}
foo(20); // you can bind Rvalue to const Lvalue reference

Несколько слов о векторе. operator[] для vector<T>, где T - это каждый тип, кроме возвращаемых bool T&:

T& vector<T>::operator[](index) // where T is not bool

Для bool векторный шаблон класса имеет специализацию. Значения bool хранятся для хранения одного бита, поскольку вы не можете использовать оператор адреса для одного бита, vector<bool>::operator[](index) не может вернуть ссылку. vector<bool> имеет внутренний класс proxy , который управляет битами (этот класс называется reference ).

vector<bool>::reference vector<bool>::operator[](index)
              ^^^^^^^^^  

как вы видите объект proxy передается по значению. Поэтому, когда вы звоните

return std::exchange(lifeTimes[index], false);

вы передаете временную объективность (Rvalue) в exchange, который принимает первый аргумент по ссылке на неконстантное Lvalue. Это причина того, что G ++ отказывается от этого кода. Если вы хотите скомпилировать его, вы можете явно создать объект Lvalue класса proxy и передать его:

  bool kill(std::size_t index)
  {
      std::vector<bool>::reference proxyForBit = lifeTimes[index];
    return std::exchange(proxyForBit, false);
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...