guide - template function c++
error: no se puede enlazar ''std:: basic_ostream<char>'' lvalue a ''std:: basic_ostream<char> &&'' (2)
Ya he analizado un par de preguntas al respecto, específicamente el operador de sobrecarga <<: no puede vincular lvalue a ''std :: basic_ostream <char> &&'' fue muy útil. Me hizo saber que mi problema es que estoy haciendo algo que c ++ 11 no puede deducir del tipo.
Creo que una gran parte de mi problema es que la clase instanciada con la que estoy trabajando está modelada, pero originalmente se obtuvo de un puntero a una clase base que no es de plantilla. Esto es algo que aconsejé de otra pregunta de stackoverflow.com sobre cómo poner objetos de clase de plantilla en un contenedor STL.
Mis clases:
class DbValueBase {
protected:
virtual void *null() { return NULL; } // Needed to make class polymorphic
};
template <typename T>
class DbValue : public DbValueBase {
public:
DbValue(const T&val) { data = new T(val); }
~DbValue() { if (data) delete data; }
T *data;
const T& dataref() const { return *data; }
friend std::ostream& operator<<(std::ostream& out, const DbValue<T>& val)
{
out << val.dataref();
return out;
}
}
Y, el fragmento de código donde compila el error database.cc:530:90: error: cannot bind ''std::basic_ostream<char>'' lvalue to ''std::basic_ostream<char>&&''
ocurre:
//nb: typedef std::map<std::string,DbValueBase*> DbValueMap;
const CommPoint::DbValueMap& db_values = cp.value_map();
for (auto i = db_values.cbegin() ; i != db_values.cend() ; i++) {
// TODO: Need to implement an ostream operator, and conversion
// operators, for DbValueBase and DbValue<>
// TODO: Figure out how to get a templated output operator to
// work...
// DbValue<std::string> *k = dynamic_cast<DbValue<std::string>*>(i->second);
std::cerr << " Database field " << i->first << " should have value " << *(i->second) << endl;
}
Si mi salida intenta imprimir i->second
, se compila y se ejecuta, y veo el puntero. Si intento enviar *(i->second)
, obtengo el error de compilación. Cuando se pasa un solo paso en gdb, parece saber que i->second
es del tipo correcto
(gdb) p i->second
$2 = (DbValueBase *) 0x680900
(gdb) p *(i->second)
warning: RTTI symbol not found for class ''DbValue<std::string>''
$3 = warning: RTTI symbol not found for class ''DbValue<std::string>''
{_vptr.DbValueBase = 0x4377e0 <vtable for DbValue<std::string>+16>}
(gdb) quit
Espero que esté haciendo algo sutilmente incorrecto. Pero es más complicado de lo que parece ser capaz de resolverlo por mi cuenta. ¿Alguien más ve qué cosa (s) he hecho mal o incompletamente?
Editar:
@PiotrNycz dio una buena solución para mi problema propuesto a continuación. Sin embargo, a pesar de que actualmente imprimo valores mientras DbValue<>
desarrollo, la necesidad real de estos objetos DbValue<>
es hacer que devuelvan un valor del tipo correcto que luego puedo pasar a los métodos de operación de la base de datos. Debería haber mencionado que en mi pregunta original, esa impresión es valiosa, pero no el final de mi objetivo.
Aunque el depurador identifica correctamente *(i->second)
como del tipo DbValue<std::string>
, esa determinación se realiza utilizando información que solo está disponible en el tiempo de ejecución.
El compilador solo sabe que está trabajando con un DbValueBase&
y tiene que generar su código sobre esa base. Por lo tanto, no puede usar el operator<<(std::ostream&, const DbValue<T>&)
ya que no acepta un DbValueBase
o subclase.
Para obtener el contenido de un objeto DbValue<>
través de un DbValueBase&
, es posible que desee ingresar al patrón de diseño del visitante.
Un código de ejemplo:
class Visitor {
public:
template <typename T>
void useValue(const T& value);
};
class DbValueBase {
public:
virtual void visit(Visitor&) = 0;
};
template <class T>
class DbValue : public DbValueBase {
pblic:
void visit(Visitor& v) {
v.useValue(m_val);
}
private:
T m_val;
};
Si desea imprimir el objeto por el puntero base, haga que el operador ostream esté en la clase base:
class DbValueBase {
protected:
virtual ~DbValueBase() {}
virtual void print(std::ostream&) const = 0;
friend std::ostream& operator << (std::ostream& os, const DbValueBase & obj)
{
obj.print(os); return os;
}
};
template <typename T>
class DbValue : public DbValueBase {
public:
void print(std::ostream& os) const
{
out << dataref();
}
};