c++ c++11 language-lawyer implicit-conversion reference-wrapper

c++ - Problema con std:: reference_wrapper



c++11 language-lawyer (2)

El problema está claro con el siguiente código:

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

Si uso el std::vector<int> a, b; comentado std::vector<int> a, b; en lugar de int a = 0, b = 0; , entonces el código no se compila en GCC 5.1, clang 3.6 o MSVC''13. En mi opinión, std::reference_wrapper<std::vector<int>> es implícitamente convertible a std::vector<int>& que es LessThanComparable, y por lo tanto debería ser LessThanComparable. ¿Podría alguien explicarme esto?


El problema es que el operator< no miembro operator< para std::vector es una plantilla de función:

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

Las conversiones implícitas no se tienen en cuenta al hacer una deducción de tipo de plantilla aquí, con énfasis en [temp.arg.explicit] si:

Las conversiones implícitas (Cláusula 4) se realizarán en un argumento de función para convertirlo al tipo del parámetro de función correspondiente si el tipo de parámetro no contiene parámetros de plantilla que participan en la deducción de argumento de plantilla.

Pero en este caso, el tipo de parámetro participa en la deducción. Por eso no se puede encontrar. Si hubiéramos escrito nuestro propio operator< no de plantilla operator< :

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

Su código funcionaría como se esperaba. Para usar el genérico, sin embargo, tendrá que sacar explícitamente la referencia:

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


Estas seguro que

std::vector<int> a, b;

¿Está haciendo lo que se supone que debe hacer? Toma esto por ejemplo

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

Lo que resulta en

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

Por último

std::vector<int> a, b;

Crea dos vectores separados de enteros llamados a y b, los cuales no tienen contenido; no es así como se declararía un solo vector con los miembros a y b.

int a=0, b=0;

Declara dos enteros separados llamados a y b, cada uno de los cuales tiene un valor de 0. Esos dos fragmentos de código declaran variables completamente diferentes y no se deben usar de manera intercambiable.