El compilador de C ++ no puede encontrar la función (relacionado con el espacio de nombres)

StackOverflow https://stackoverflow.com/questions/493985

Pregunta

Estoy trabajando en Visual Studio 2008 en una asignación de programación C ++. Se nos proporcionaron archivos que definen la siguiente jerarquía de espacio de nombres (los nombres son solo por el bien de esta publicación, sé & Quot; espacio de nombres XYZ-NAMESPACE & Quot; es redundante):

(MAIN-NAMESPACE){

      a bunch of functions/classes I need to implement...

      (EXCEPTIONS-NAMESPACE){

            a bunch of exceptions
      }

      (POINTER-COLLECTIONS-NAMESPACE){

            Set and LinkedList classes, plus iterators
      }
}

El contenido de MAIN-NAMESPACE se divide entre un montón de archivos y, por alguna razón, no entiendo el operador < < tanto para Set como para LinkedList está completamente fuera de MAIN-NAMESPACE (pero dentro del archivo de encabezado de Set y LinkedList). Aquí está la versión Set:

template<typename T>
std::ostream& operator<<(std::ostream& os, 
                         const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set<T>& set)

Ahora, aquí está el problema: tengo la siguiente estructura de datos:

Set A
Set B
Set C
double num

Se define para estar en una clase dentro de MAIN-NAMESPACE. Cuando creo una instancia de la clase e intento imprimir uno de los conjuntos, me dice que: error C2679: binario '< <' : no se encontró ningún operador que tome un operando a la derecha del tipo 'const MAIN-NAMESPACE :: POINTER-COLLECTIONS-NAMESPACE :: Set' (o no hay una conversión aceptable)

Sin embargo, si solo escribo una función main (), y creo el Conjunto A, lo relleno y uso el operador, funciona.

¿Alguna idea de cuál es el problema? (nota: probé cualquier combinación de uso e inclusión que se me ocurriera).

¿Fue útil?

Solución 2

OK, descubrí esto. La intuición de jpalecek acerca de que existe otro operador < < en el espacio de nombres era correcto (aparentemente olvidé comentarlo).

Las reglas de búsqueda para espacios de nombres comienzan primero la búsqueda en el espacio de nombres de la llamada de función y buscan los espacios de nombres adjuntos, hasta el espacio de nombres global (luego realiza la búsqueda dependiente de Argumento si no se encuentra ninguna coincidencia). Sin embargo, si en el camino encuentra alguna coincidencia para el operador & Lt; & Lt ;, detiene la búsqueda, independientemente del hecho de que los tipos utilizados en esas funciones pueden ser incompatibles, como fue el caso aquí.

La solución es incluirlo en el ESPACIO PRINCIPAL (que no se me permite), o importarlo desde el espacio de nombres global con " usando :: operator < < " ;.

Otros consejos

Extraño: aunque poner funciones libres asociadas con un tipo en un espacio de nombres diferente es una mala práctica, las declaraciones de espacios de nombres globales siempre son visibles.

Lo único en lo que puedo pensar es que la declaración con el mismo nombre en MAIN-NAMESPACE sombrearía la del espacio de nombres global, ¿no hay un operator<<, posiblemente para un tipo totalmente no relacionado, en using ::operator<<? Si es así, debe solucionarlo mediante <=> declaración en <=>. Ejemplo:

namespace A
{
namespace B
{
  class C{};
}

}

void f(A::B::C*);

namespace A
{
  void f(int*); // try commenting
  using ::f; // these two lines
  void g()
  {
    B::C* c;
    f(c);
  }
}

¿Intenta llamar a la función explícitamente?

::operator<<( cout, myObj );

Como SoaBox señaló, intente llamarlo explícitamente.

Para su información, si desea llamar a una función global que se ha ocultado en el espacio de nombres actual, preceda la función con :: para omitir la función local y llamar a la función global.

  

¿Intenta llamar a la función explícitamente?

     

:: operador < < (cout, myObj);

¡Sí, eso funciona!

  

intentará encontrar la función f en   el espacio de nombres actual (en el lugar de   llamada) o en los espacios de nombres adjuntos   de los tipos c1 y c2 (namespace1,   namespace2 :: namespace3), pero lo hará   no intente otros espacios de nombres en el   buscar.

Entonces, veamos si acerté: la razón para invocar al operador < < desde una función main () trabajada es porque estaba en el espacio de nombres global (como estaba el operador < <). La razón por la que falló al invocar desde la clase que implementé es porque la clase estaba en un espacio de nombres no global y no había variables que apuntaran al compilador hacia el espacio de nombres global.

OK, las personas pidieron ejemplos específicos, así que aquí está la parte relevante del código. // Descargo de responsabilidad: en el caso delgado, alguien de mi universidad lo ve, lo encuentra en el archivo de envío y decide que lo copié o algo, mi número de estudiante es 311670137

Este es el archivo de encabezado Set.h:

   namespace MTM {//This is the MAIN-NAMESPACE

    namespace PointerCollections {

        (ITERATORS AND PREDICATE CLASSES)

        template<typename T>
        class Set {
        public:

        /////////////////////////////////
        // Definitions
        /////////////////////////////////

        private:

        /////////////////////////////////
        // Definitions
        /////////////////////////////////

        };


///////////////////////////////////////////////////////////////////////////////
// The implementation part. 
///////////////////////////////////////////////////////////////////////////////
      }
}
// operator<< - the same a Set::print(std::ostream& os,
//                                    const BinaryPredicate<T>& predicate) 
// function called with the 'predicate' parameter omitted
template<typename T>
std::ostream& operator<<(std::ostream& os, 
                         const MTM::PointerCollections::Set<T>& set){

    set.print(os);
    return os;
}

Esto es lo que definí en un archivo diferente:

namespace MTM {
    using std::ostream;

    class Schedule {
    public:
      ///////////////////
      //Definitions, including: 
      ///////////////////
    void registerStation(string stationName);
    void reportRegisteredStations(std::ostream& outputStream) const;

    private:     //My database
               //All the classes Set recieves are defined elsewhere
        Set<RegisteredStation> places;
        Set<BusLine> busses;
        Set<TrainLine> trains;
        double tarifForBuses;
        double tarifForTrains;
    };

}

Y aquí está lo principal:

Schedule s();
s.registerStation("1");
s.reportRegisteredStations(cout);//This invokes the error. Definition follows:

reportRegisteredStations se define como:

void Schedule::reportRegisteredStations(std::ostream& outputStream) const{

        outputStream<<places;
    }

Esto funciona para mí

#include <iostream>
#include <string>
using std::string;

   namespace MTM {//This is the MAIN-NAMESPACE

    namespace PointerCollections {

        template<typename T>
        class Set {
        };


      }
}
template<typename T>
std::ostream& operator<<(std::ostream& os, 
                         const MTM::PointerCollections::Set<T>& set){

    return os;
}

namespace MTM {
    using std::ostream;
  using PointerCollections::Set;
    class Schedule {
    public:
      ///////////////////
      //Definitions, including: 
      ///////////////////
    void registerStation(string stationName);
    void reportRegisteredStations(std::ostream& outputStream) const;

    private:     //My database
               //All the classes Set recieves are defined elsewhere
        Set<int> places;
        Set<int> busses;
        Set<int> trains;
        double tarifForBuses;
        double tarifForTrains;
    };
void Schedule::reportRegisteredStations(std::ostream& outputStream) const{

        outputStream<<places;
    }

}

int main()
{
  MTM::Schedule s;
  s.reportRegisteredStations(std::cout);
}

CORRECCIÓN : el texto a continuación se basa en la experiencia con la familia de compiladores g ++. Después del comentario a la respuesta, he releído el estándar (que establece que se usará ADL sobre la búsqueda de nombre regular, y la búsqueda de nombre regular debería encontrar el operador & Lt; & Lt;). También probé con el compilador comeau (el compilador compatible más estándar que conozco) y se encuentra el símbolo. Parece un problema con g ++ (versiones probadas 3.3, 4.1, 4.3).

Respuesta original:

Busque la búsqueda de Koening (técnicamente ADL: búsqueda dependiente del argumento).

La respuesta corta es que si tiene la siguiente clase:

namespace test {
    class A {};
}

el operador de inserción de flujo debe definirse como:

namespace test {
    std::ostream& operator<<( std::ostream&, A const & );
}

Las funciones u operadores deben definirse en el mismo espacio de nombres que uno de los argumentos que toma. (*)

Cuando el compilador encuentra una llamada de función como:

namespace test2 {
   void g() {
      namespace1::class1 c1;
      namespace2::namespace3::class2 c2;
      f( c1, c2 );
   }
}

intentará encontrar la función f en el espacio de nombres actual (en el lugar de la llamada) o en los espacios de nombres adjuntos de los tipos c1 y c2 (namespace1, namespace2 :: namespace3), pero no intentará otros espacios de nombres en la búsqueda.

(*) En este caso, está bastante limitado al espacio de nombres prueba , ya que no puede agregar una función al espacio de nombres estándar (solo especializaciones de plantilla).

Fin de la publicación original .

Incluso si como se comentó anteriormente, esto puede ser un problema con el compilador, es de uso común y se recomienda definir todas las funciones libres que operan en un tipo definido por el usuario en el mismo espacio de nombres que el tipo en sí.

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