Подтвердить что ты не робот

Проблема с std:: reference_wrapper

Проблема понятна с помощью следующего кода:

#include <functional>
#include <iostream>
#include <vector>

int main() {
  //std::vector<int> a, b;
  int a = 0, b = 0;
  auto refa = std::ref(a);
  auto refb = std::ref(b);
  std::cout << (refa < refb) << '\n';
  return 0;
}

Если я использую комментарий std::vector<int> a, b; вместо int a = 0, b = 0;, тогда код не компилируется ни на одном из GCC 5.1, clang 3.6 или MSVC'13. По-моему, std::reference_wrapper<std::vector<int>> неявно конвертируется в std::vector<int>&, который является LessThanComparable, и, следовательно, он должен быть сам LessThanComparable. Может ли кто-нибудь объяснить это мне?

4b9b3361

Ответ 1

Проблема заключается в том, что не-член operator< для std::vector является шаблоном функции:

template< class T, class Alloc >
bool operator<( const vector<T,Alloc>& lhs,
                const vector<T,Alloc>& rhs );

Неявные преобразования не учитываются при выводе типа шаблона здесь [temp.arg.explicit], если:

Неявные преобразования (раздел 4) будут выполняться на аргументе функции, чтобы преобразовать его в тип соответствующий параметр функции , если, тип параметра не содержит шаблонных параметров, которые участвуют в выводе аргумента шаблона.

Но в этом случае тип параметра участвует в вычете. Вот почему его не найти. Если бы мы написали собственный собственный шаблон operator<:

bool operator<(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
    return true;
}

Ваш код будет работать так, как ожидалось. Чтобы использовать общий вариант, вам придется явно вывести ссылку:

std::cout << (refa.get() < refb.get()) << '\n';

Ответ 2

Вы уверены, что

std::vector<int> a, b;

Делает то, что он должен делать? Возьмите это, например,

#include <functional>
#include <iostream>
#include <vector>

int main() {
  std::vector<int> a, b;
  //int a = 0, b = 0;
  a.push_back(42);
  a.push_back(6);
  a.push_back(15);
  for (int ii=0; ii<43; ii++) {
    b.push_back(ii);
  }
  auto refa = std::ref(a);
  auto refb = std::ref(b);
  std::cout<<&refa<<std::endl;
  std::cout<<&refb<<std::endl;
  std::cout<<"Contents of vector A"<<std::endl;
  for(auto n : a)
  {
    std::cout<<' '<<n;
  }
  std::cout<<std::endl<<"Contents of vector b: ";
  for (auto n : b){
    std::cout<<' '<<n;
  }
  //std::cout << (refa < refb) << '\n';
  return 0;
}

В результате получается

0x7fff5fbff0c0
0x7fff5fbff0b8
Contents of vector A
 42 6 15
Contents of vector b:  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

В конечном счете

std::vector<int> a, b;

Создает два отдельных вектора целых чисел a и b, оба из которых не имеют содержимого; это не так, как можно объявить один вектор с членами a и b.

int a=0, b=0;

Объявляет два отдельных целых числа a и b, каждое из которых имеет значение 0. Эти два фрагмента кода объявляют совершенно разные переменные и не должны использоваться взаимозаменяемо.