2011-01-21 9 views
8

Tengo operadores declarados para la clase my_type en el espacio de nombres my_namespace.gcc failes para compilar la definición del operador con el espacio de nombres prefijado

namespace my_namespace { 
class my_type 
{ 
    friend std::ostream& operator << (std::ostream& out, my_type t); 
} 
} 

Estoy tratando de definir estos operadores en el archivo de implementación, pero cuando escribo algo así

std::ostream& my_namespace::operator << (std::ostream& out, my_type t) 
{ 
out << t; 
return out; 
} 

Puedo obtener mensaje de error

error: ... operator should have been declared inside 'my_namespace'

Cuando lo cambio a

namespace my_namespace { 
    std::ostream& operator << (std::ostream& out, my_type t) 
    { 
    out << t; 
    return out; 
    } 
} 

luego compila, pero no entiendo el problema. ¿Por qué no se pudo compilar? ¿Hay todo lo correcto con eso? Agradecería el enlace al estándar ya que realmente no sé qué buscar.

añade

file.h

#ifndef A_H 
#define A_H 

#include <iosfwd> 

namespace N 
{ 
class A 
{ 
    friend std::ostream& operator << (std::ostream& out, A& obj); 
}; 
} 

#endif 

file.cpp

#include "file.h" 
#include <iostream> 

std::ostream& N::operator << (std::ostream& out, N::A& obj) 
{ 
return out; 
} 

int main() {} 

aquí es ejemplo completo. Esto funciona bien en VS2010, pero proporciona el error mencionado anteriormente en gcc 4.4.5.

añade

hmm ... sí, éste funciona

namespace N 
{ 
    class A 
    { 
     friend std::ostream& operator << (std::ostream& out, A& obj); 
    }; 
    std::ostream& operator << (std::ostream& out, A& obj); 
} 

Siempre estaba pensando que en términos de visibilidad del operador se declara amigo en clase es lo mismo que declarar fuera de la clase .. parece que no lo es. Gracias.

Muchas gracias de antemano.

+0

En GCC, compilar esto con la opción '-ffriend-injection' tendrá éxito. – user7610

Respuesta

9

El mensaje de error lo dice todo, en realidad. Usted puede mantener su definición de la función en el archivo de implementación, pero hay que declararlo en el espacio de nombres en primer lugar:

namespace my_namespace { 
    std::ostream& operator << (std::ostream& out, my_type t); 
} 

El estándar de C++ es bastante claro al respecto:

7.3.1.2/ 3:

Todos los nombres declarados por primera vez en un espacio de nombres son miembros de ese espacio de nombres. Si una declaración de amigo en una clase no local declara primero una clase o función, la clase o función amiga es un miembro del espacio de nombre más interno que lo rodea. El nombre del amigo no se encuentra por simple búsqueda de nombre hasta que se proporcione una declaración coincidente en ese ámbito de espacio de nombres (ya sea antes o después de la declaración de clase que otorga la amistad). Si se llama a una función amiga, su nombre se puede encontrar mediante la búsqueda de nombres que considera funciones de espacios de nombres y clases asociadas con los tipos de argumentos de función (3.4.2).Cuando se busca una declaración previa de una clase o una función declarada como amigo, y cuando el nombre de la clase o función amiga no es ni un nombre calificado ni una plantilla, no se consideran los ámbitos fuera del alcance del espacio de nombres más interno. .

El siguiente enlace pone más simple, y añade algunos ejemplos: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr043.htm

así que diría que gcc es malo aquí. . La frase relevante parece ser "El nombre del amigo no se encuentra buscando nombres simples hasta que se proporcione una declaración coincidente en ese ámbito de espacio de nombres (ya sea antes o después de la declaración de clase que otorga amistad).

+2

Ya está declarado en el espacio de nombres (en el archivo de encabezado), ¿no? – ledokol

+0

No: "El nombre de una función amiga o clase presentada por primera vez en una declaración de amigo no está dentro del alcance de la clase que otorga amistad. El nombre de una función que se introdujo primero en una declaración de amigo está en el alcance del primer alcance no contiene la clase adjunta ". (http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr043.htm) –

+0

... lo que significa que están en lo cierto ... Solo una pregunta: de hecho incluiste tu archivo de cabecera en el archivo fuente, ¿verdad? Y hubo un ';' después del cierre '};' de la declaración de clase? –

1

Las declaraciones se refieren a un conjunto de otros nombres e introduzca un único nombre nuevo; este nuevo nombre no debe calificarse con un identificador de espacio de nombres, sino que la declaración debe estar dentro del bloque de espacio de nombres en el que debe declararse el nuevo nombre.

Las mismas reglas se aplican a las definiciones, ya que implican una declaración. La declaración de amigo es especial, porque vive dentro de otra definición y realmente no declara nada.

Cuestiones relacionadas