sobrecarga que operator operadores operador numeros insercion extraccion esta definicion compuesta complejos c++

c++ - que - Operador de sobrecarga<<: no puede vincular lvalue a ''std:: basic_ostream<char> &&''



sobrecarga de operadores numeros complejos (3)

Bo proporcionó la razón por la que esto está sucediendo (el tipo T no es deducible en la llamada al operator<< anidado operator<< . Una solución simple para esto, y algo que recomiendo en general, no solo aquí, no es hacer amistad con una plantilla, sino más bien una única función libre. Para eso, necesitarás definir la función en línea:

template<typename T> struct classA { struct classB { friend inline std::ostream& operator<< (std::ostream &out, const classB &b) { // definition goes here } }; classB root; friend std::ostream& operator<< (std::ostream &out, const classA<U> &tree) { // definition goes here } };

Hay un par de diferencias entre los dos enfoques. El más importante es que este enfoque hará que el compilador defina una sobrecarga sin plantilla para el operator<< para cada instanciación de la plantilla, que como ya no es una plantilla, no depende de deducir los argumentos. Otros efectos secundarios son que el enfoque es un poco más estricto (solo se está haciendo amigo de una función, mientras que en su enfoque inicial se hizo amigo de la plantilla y todas las instancias posibles (que pueden usarse como una laguna para acceder a su clase interna). las funciones así definidas solo se encontrarán a través de ADL, por lo que hay menos sobrecargas del operator<< para que el compilador ClassA<T> en cuenta cuando el argumento no es ClassA<T> o ClassA<T>::ClassB .

Cómo se puede obtener acceso con su enfoque

namespace { struct intruder { ClassA & ref; intruder( ClassA& r ) : ref(r) {} }; template <> std::ostream& operator<< <intruder>( std::ostream& _, ClassA<intruder> const& i ) { std::cout << i.ref.private_member << std::endl; return _; } }

Alternativa

Alternativamente, puede hacerse amigo de una especialización particular de una plantilla. Eso resolverá el problema del intruder , ya que solo estará abierto para el operator<< a ClassA<intruder> , que tiene un impacto mucho menor. Pero esto no resolverá su problema en particular, ya que el tipo aún no sería deducible.

Tengo una clase que usa una clase anidada, y quiero usar el operator<< clase anidado operator<< para definir el operator<< en la clase superior. Así es como se ve mi código:

#include <memory> #include <iostream> template<typename T> struct classA { struct classB { template<typename U> friend inline std::ostream& operator<< (std::ostream &out, const typename classA<U>::classB &b); }; classB root; template<typename U> friend std::ostream& operator<< (std::ostream &out, const classA<U> &tree); }; template<typename T> inline std::ostream& operator<< (std::ostream &out, const classA<T> &tree) { out << tree.root; return out; } template<typename T> inline std::ostream& operator<< (std::ostream &out, const typename classA<T>::classB &b) { return out; } int main() { classA<int> a; std::cout << a; }

  • Al compilar sin soporte para C ++ 11, la definición de operador << para la clase interna parece no ser encontrada por el compilador:

    so.hpp:24:7: error: no match for ‘operator<<’ in ‘out << tree.classA<int>::root’ so.hpp:24:7: note: candidates are: ...

  • Con GCC 4.6 y 4.7 al compilar con std = c ++ 0x:

    so.hpp:21:3: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’ In file included from /usr/include/c++/4.7/iostream:40:0, from so.hpp:2: /usr/include/c++/4.7/ostream:600:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = classA<int>::classB]’

¿Puede alguien decirme por qué este código no es legal y cuál es la mejor manera de hacer lo que quiero?


Prueba esto:

template<typename T> inline std::ostream& operator<< (std::ostream &out, const classA<T> &tree) { //out << tree.root; ::operator<<( out, tree.root); return out; }

y luego obtendrás una confesión directa de ineptitud:

test.cpp:34:3: error: no matching function for call to ‘operator<<(std::ostream&, const classA<int>::classB&)’ test.cpp:34:3: note: candidates are: test.cpp:23:22: note: template<class T> std::ostream& operator<<(std::ostream&, const typename classA<T>::classB&) test.cpp:30:22: note: template<class T> std::ostream& operator<<(std::ostream&, const classA<T>&)

Solución: quizás pueda usar una función de miembro en el classB anidado, y usarla en lugar del operador << ... Por supuesto, esa solución tiene una multitud de inconvenientes, pero puede sacarlo de esta prisa.


Tiene un problema con un "contexto no deducible" en este operador

template<typename T> inline std::ostream& operator<< (std::ostream &out, const typename classA<T>::classB &b) { return out; }

El compilador no puede determinar qué valores de T resultarán en una classB que coincida con el parámetro que desea aprobar. ¡Entonces esta plantilla no es considerada!

En el modo C ++ 11, el compilador luego busca una coincidencia cercana de la biblioteca estándar

operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&)

donde puede hacer coincidir _Tp con cualquier tipo, incluida classA<T>::classB , pero observa que el primer parámetro no coincide.