librerias libreria geeksforgeeks functions estandar dev c++ stl

libreria - stl class c++



¿Por qué recibo un error en el mapa "formando referencia al tipo de referencia"? (5)

Esencialmente, la pregunta es si puedes usar referencias en contenedores . Por supuesto, usted puede, SI prepara adecuadamente su clase Y su contenedor. Lo demuestro a continuación con dos contenedores de vectores simples: vectoref que modifica std::vector<> y el otro, vec , que se implementa desde cero.

#include <iostream> #include <vector> // requires compilation with --std=c++11 (at least) using namespace std; class A { int _a; // this is our true data A *_p; // this is to cheat the compiler public: A(int n = 0) : _a(n), _p(0) { cout << "A constructor (" << this << "," << _a << ")/n"; } // constructor used by the initializer_list (cheating the compiler) A(const A& r) : _p(const_cast<A *>(&r)) { cout << "A copy constructor (" << this << "<-" << &r << ")/n"; } void print() const {cout << "A instance: " << this << "," << _a << "/n";} ~A() {cout << "A(" << this << "," << _a << ") destructor./n";} // just to see what is copied implicitly A& operator=(const A& r) { cout << "A instance copied (" << this << "," << _a << ")/n"; _a = r._a; _p = r._p; return *this; } // just in case you want to check if instance is pure or fake bool is_fake() const {return _p != 0;} A *ptr() const {return _p;} }; template<typename T, int sz> class vec { // vector class using initializer_list of A-references!! public: const T *a[sz]; // store as pointers, retrieve as references // because asignment to a reference causes copy operator to be invoked int cur; vec() : cur(0) {} vec(std::initializer_list<T> l) : cur(0) { cout << "construct using initializer list./n"; for (auto& t : l) // expecting fake elements a[cur++] = t.ptr(); } const T& operator[](int i) {return *a[i];} // expecting pure elements vec& push_back(const T& r) {a[cur++] = &r; return *this;} void copy_from(vec&& r) { for (int i = 0; i < r.cur; ++i) push_back(r[i]); } }; template<typename T> class vectoref : public vector<T *> { // similar to vec but extending std::vector<> using size_type = typename vector<T*>::size_type; public: vectoref() {} vectoref(std::initializer_list<T> l) { cout << "construct using initializer list./n"; for (auto& t : l) // expecting fake elements vector<T*>::push_back(t.ptr()); } const T& operator[](size_type i) {return *vector<T*>::at(i);} // expecting pure elements vectoref& push_back(const T& r) { vector<T*>::push_back(&r); return *this; } void copy_from(const vectoref&& r) { for (size_type i = 0; i < r.size(); ++i) vectoref<T>::push_back(r[i]); } }; class X { // user of initializer_list of A public: X() {} void f(initializer_list<A> l) const { cout << "In f({...}):/n"; for (auto& a : l) a.ptr()->print(); } }; int main() { A a(7), b(24), c(80); cout << "----------------------------------/n"; vectoref<A> w{a,a,b,c}; // alternatively, use next line // vec<A,5> w{a,a,b,c}; // 5-th element undefined w[0].print(); w[3].print(); cout << "----------------------------------/n"; X x; x.f({a,b,c,a,b,c,b,a}); cout << "==================================/n"; return 0; }

¿Cuál es la alternativa si necesito usar una referencia y los datos que estoy transmitiendo no puedo cambiar el tipo de, por lo tanto, realmente no puedo almacenar un puntero?

Código:

#include <map> #include<iostream> #include<string> using namespace std; int main() { string test; pair<string, string> p=pair<string, string>("Foo","Bar"); map<pair<string, string>, string&> m; m[make_pair("aa","bb")]=test; return 0; }

Error:

$ g ++ MapPair.cpp /usr/include/c++/3.2.3/bits/stl_map.h: En la instanciación de std::map<std::pair<std::string, std::string>, std::string&, std::less<std::pair<std::string, std::string> >, std::allocator<std::pair<const std::pair<std::string, std::string>, std::string&> > >'': MapPair.cpp:15:
instantiated from here /usr/include/c++/3.2.3/bits/stl_map.h:221: forming reference to reference type
std::map<std::pair<std::string, std::string>, std::string&, std::less<std::pair<std::string, std::string> >, std::allocator<std::pair<const std::pair<std::string, std::string>, std::string&> > >'': MapPair.cpp:15:
instantiated from here /usr/include/c++/3.2.3/bits/stl_map.h:221: forming reference to reference type
std::map<std::pair<std::string, std::string>, std::string&, std::less<std::pair<std::string, std::string> >, std::allocator<std::pair<const std::pair<std::string, std::string>, std::string&> > >'': MapPair.cpp:15:
instantiated from here /usr/include/c++/3.2.3/bits/stl_map.h:221: forming reference to reference type
std :: string & ''MapPair.cpp: In function int main()'': MapPair.cpp:16: no match for std :: map, std :: string &, std :: less>,
std :: asignador,
std :: string &>>> & [std :: pair] ''operator /usr/include/c++/3.2.3/bits/stl_pair.h: En el ámbito global: /usr/include/c++/3.2.3/bits/ stl_pair.h: En la instanciación de std::pair<const std::pair<std::string, std::string>, std::string&>'': /usr/include/c++/3.2.3/bits/stl_tree.h:122: instantiated from std :: _ Rb_tree_node

¿Qué estoy haciendo mal para causar este error?


Las respuestas anteriores aquí están desactualizadas. Hoy tenemos std::reference_wrapper como parte del estándar C ++ 11:

#include <map> #include <iostream> #include <string> using namespace std; int main() { string test; pair<string, string> p = pair<string, string>("Foo", "Bar"); map<pair<string, string>, reference_wrapper<string>> m; m[make_pair("aa", "bb")] = test; return 0; }

A std :: reference_wrapper se convertirá implícitamente en una referencia a su tipo interno, pero esto no funciona en algunos contextos, en cuyo caso llama a .get() para acceder.

http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper


No puede almacenar referencias. Las referencias son solo alias de otra variable .

El mapa necesita una copia de la cadena para almacenar:

map<pair<string, string>, string> m;

La razón por la que está recibiendo ese error en particular es porque en algún lugar del mapa, va a realizar una operación en el tipo de mapped_type que en su caso es string& . Una de esas operaciones (como en el operator[] , por ejemplo) devolverá una referencia al tipo de mapped_type :

mapped_type& operator[](const key_type&)

Que, con tu mapped_type , sería:

string&& operator[](const key_type& _Keyval)

Y no puedes tener una referencia a una referencia:

Estándar 8.3.4:

No debe haber referencias a referencias, ni matrices de referencias, ni punteros a referencias.

En una nota al margen, te recomendaría que uses typedef ''s para que tu código sea más fácil de leer:

int main() { typedef pair<string, string> StringPair; typedef map<StringPair, string> StringPairMap; string test; StringPair p("Foo","Bar"); StringPairMap m; m[make_pair("aa","bb")] = test; return 0;

}


No se pueden usar referencias como val, debido a cómo se construye la plantilla. También podría utilizar el puntero en su lugar.


Puede usar boost :: reference_wrapper para almacenar referencias en contenedores STL. Aquí está su ejemplo modificado (no probado, y definitivamente no muy bien escrito, solo ilustra un punto)

#include <map> #include<iostream> #include<string> #include <boost/ref.hpp> int main() { typedef std::pair< std::string, std::string> PairType; typedef std::map< PairType, boost::reference_wrapper<std::string> > MapType; std::string test = "Hello there!!"; MapType m; PairType pp = std::make_pair("aa","bb"); m.insert(std::make_pair(pp , boost::ref(test) ) ); MapType::iterator it (m.find( pp ) ); if(it != m.end()) { std::cout << it->second.get() << std::endl; } //change test test = "I am different now"; std::cout << it->second.get() << std::endl; return 0; }