Pregunta

Al escribir una clase para actuar como un envoltorio alrededor de un objeto heap-asignado, me encontré con un problema con la conversión de tipo implícito de que se puede reducir a este sencillo ejemplo.

En el código por debajo de la clase de contenedor gestiona un objeto heap-asignado e implícitamente se convierte en una referencia a ese objeto. Esto permite que el objeto contenedor que se pasa como argumento a la función de escritura (...) ya la conversión implícita tiene lugar.

El compilador falla, sin embargo, cuando se trata de resolver la llamada al operador << (...), a menos que se haga una conversión explícita (comprobado con MSVC8.0, Intel 9.1 y gcc 4.2.1 compiladores).

Así que, (1) ¿Por qué falla la conversión implícita en este caso? (2) podría estar relacionado con las operaciones de búsqueda argumento dependiente? y (3) ¿hay algo que se puede hacer para hacer este trabajo sin la conversión explícita?

#include <fstream>

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

void write(std::ostream& os)
{
    os << "(1) Hello, world!\n";
}

int main()
{
    wrapper<std::ostream> file(new std::ofstream("test.txt"));

    write(file);
    static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
    // file << "(3) This line doesn't compile!\n";
}
¿Fue útil?

Solución

Se produce un error debido a que estamos tratando de resolver un operador de la clase wrapper<T> que no existe. Si quieres que funcione sin el molde, se puede armar algo como esto:

template<typename X> wrapper<T> &operator <<(X &param) const {
    return t << param;
}

Por desgracia, no sé de una manera de resolver el tipo de retorno en tiempo de compilación. Afortunadamente, en la mayoría de los casos es el mismo tipo que el objeto, incluyendo en este caso con ostream.

EDIT: código Modificado por sugerencia de guión-tom-bang. Cambió el tipo de retorno a wrapper<T> &.

Otros consejos

El compilador no tiene contexto suficiente para determinar que operator& hará una conversión válida. Así que, sí, creo que esto está relacionado con las operaciones de búsqueda argumento dependiente: El compilador está buscando una operator<< que puede aceptar un const no wrapper<std::ostream> como primer parámetro

.

Creo que el problema tiene que ver con el mantenimiento de algunas limitaciones de tiempo de compilación. En su ejemplo, el compilador primero tendría que encontrar todos la posible operador <<. Luego, para cada uno de ellos, se debe probar si el objeto se puede convertir de forma automática (directa o indirectamente) a cualquiera de los tipos que cada operador << son capaces de aceptar.

Esta prueba puede ser muy compleja, y creo que esto se limita a proporcionar un tiempo de compilación razonable.

Después de algunas pruebas, un ejemplo aún más simple identifica la fuente del problema. El compilador no puede deducir el argumento de plantilla en T f2(const bar<T>&) por debajo de la conversión implícita de wrapper<bar<int> > a bar<int>&.

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

class foo { };

template <typename T> class bar { };

void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }

int main()
{
    wrapper<foo> s1(new foo());
    f1(s1);

    wrapper<bar<int> > s2(new bar<int>());
    //f2(s2); // FAILS
    f2<int>(s2); // OK
    f3(s2);
}

En el ejemplo original, std::ostream es en realidad un typedef para la std::basic_ostream<..> clase de plantilla, y la misma situación se aplica cuando se llama a la función operator<< plantilla.

Comprobar la firma del operador de inserción ... Creo que tomar referencia ostream no constante?

Confirmado con C ++ 03 estándar, la firma del operador char * salida es:

template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);

que tiene efectivamente una referencia no const. Por lo que su operador de conversión no coincide.

Como se señaló en el comentario:. Este es irrelevante

Hay varios límites de la Norma sobre las conversiones aplicadas ... tal vez esto necesitaría conversiones implícitas (su operador, y el reparto de tipo base), cuando en la mayoría de ellos deberían aplicarse.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top