Frage

Ich arbeite in Visual Studio 2008 auf einer C ++ Programmieraufgabe. Wir waren mit Dateien geliefert, die die folgende Namespace-Hierarchie definieren (die Namen sind, nur um von diesem Post, ich „Namespace-XYZ-namespace“ kennen, ist redundant):

(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
      }
}

Die MAIN-namespace Inhalte werden zwischen einem Bündel von Dateien aufgeteilt, und aus irgendeinem Grund, den ich außerhalb des MAIN-namespace nicht die Betreiber verstehen << sowohl für Set und LinkedList ist ganz (aber innerhalb Set und LinkedList Header Datei). Hier ist die Set-Version:

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

Jetzt ist hier das Problem: Ich habe die folgende Datenstruktur:

Set A
Set B
Set C
double num

Es ist definiert in einer Klasse innerhalb MAIN-Namespace zu sein. Wenn ich eine Instanz der Klasse erstellen, und versuchen, einen der Sätze zu drucken, sagt es mir, dass: C2679 Fehler: binary ‚<<‘: gefunden kein Betreiber, die einen rechten Operanden vom Typ ‚const MAIN-namespace :: POINTER-KOLLEKTION-namespace :: Set‘ (oder gibt es keine akzeptable Umwandlung)

nimmt

Allerdings, wenn ich schreibe nur eine main () Funktion und Set A erstellen, füllen Sie es auf, und verwenden Sie die betreiber es funktioniert.

Jede Idee, was ist das Problem? (Anmerkung: Ich habe versucht, eine beliebige Kombination der Verwendung und bin ich denken konnte).

War es hilfreich?

Lösung 2

OK Ich dachte dies. jpalecek Intuition über einen anderen Betreiber bestehenden << im Namensraum korrekt war (anscheinend vergaß ich es auszukommen).

Die Suchregeln für Namensräume zunächst die Suche im Namensraum des Funktionsaufrufes starten und die einschließenden Namespace suchen nach oben, bis hin zu dem globalen Namensraum (dann tut es das Argument abhängige Lookup, wenn keine Übereinstimmung gefunden wird). Wenn jedoch auf dem Weg es etwas Spiel für Operator findet <<, stoppt er die Suche, unabhängig von der Tatsache, dass die Arten in diesen Funktionen nicht kompatibel sein können, wie es hier der Fall war.

Die Lösung ist entweder in den MAIN-Namespace gehört (was mir nicht erlaubt), oder aus dem globalen Namensraum importieren mit der Angabe „:: operator <<“.

Andere Tipps

Komisch - obwohl mit einem Typ in einen anderen Namespace ist eine schlechte Praxis verbunden freie Funktionen setzen, sind die globalen Namensraum-Deklarationen immer sichtbar

.

Das einzige, was ich denken kann, ist diese Erklärung mit dem gleichen Namen in MAIN-NAMESPACE die man im globalen Namespace würde Schatten - ist dort nicht ein operator<<, möglicherweise für völlig unabhängig Art, in MAIN-NAMESPACE? Wenn ja, sollten Sie, dass durch using ::operator<< Erklärung in MAIN-NAMESPACE beheben. Beispiel:

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);
  }
}

Versuchen Sie, die Funktion explizit aufrufen?

::operator<<( cout, myObj );

Wie SoaBox wies darauf hin, versuchen Sie es explizit aufrufen.

Für Ihre Informationen, wenn Sie eine globale Funktion aufrufen, die im aktuellen Namensraum versteckt wurde, vorangestellt, die Funktion mit :: die lokale Funktion umgehen und die globale Funktion aufrufen.

  

Versuchen Sie, die Funktion explizit aufrufen?

     

:: operator << (cout, myObj);

Ja, das funktioniert!

  

es wird versuchen, die f-Funktion zu finden in   der aktuelle Namensraum (am Ort des   Call) oder in den umschließenden Namensräumen   von C1- und C2-Typ (namespace1,   namespace2 :: namespace3), aber es wird   Versuchen Sie nicht, andere Namensräume in der   Suche.

Lassen Sie sich also sehen, ob ich das richtig verstanden habe: der Grund, den Betreibers Aufruf << von einer main () Funktion ist gearbeitet, weil ich in dem globalen Namensraum war (wie war Operator <<). Der Grund, es scheiterte, als aus der Klasse Aufruf ich implementiert ist, weil die Klasse in einem nicht globalen Namensraum war und es gab keine Variablen darin, die die Compiler auf der globalen Namespace hingewiesen.

OK Leute gefragt, für ein bestimmten Beispiele, so ist hier der relevante Teil des Codes. // Disclamer: in dem schlanken Fall, dass jemand aus meiner Uni dies sieht, trifft es in der Vorlage-Datei und entscheidet ich kopierte es oder etwas, mein Matrikelnummer ist 311670137

Dies ist die Header-Datei 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;
}

Dies ist, was ich in einer anderen Datei definiert:

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;
    };

}

Und hier ist von der Haupt:

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

reportRegisteredStations ist definiert als:

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

        outputStream<<places;
    }

Dies funktioniert für mich

#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);
}

KORREKTUR : Der folgende Text auf Erfahrungen mit der g ++ Familie von Compilern basiert. Nach dem Kommentar auf die Antwort habe ich den Standard wieder gelesen (die besagt, dass ADL wird gegenüber der regulären Namen-Suche verwendet werden, und regelmäßige Namenssuche sollte die Betreiber << finden). Ich habe auch versucht, mit comeau Compiler (die meisten Standard-konformen Compiler ich kenne) und das Symbol gefunden wird. Es scheint, als ein Problem mit g ++ (versucht, Versionen 3.3, 4.1, 4.3).

Original Antwort:

Suchen Sie nach Koening Nachschlag. (Technisch ADL: Argument abhängige Lookup)

Die kurze Antwort ist, dass wenn Sie die folgende Klasse:

namespace test {
    class A {};
}

der Strom-Operator soll wie folgt definiert werden:

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

Funktionen oder Operatoren sollten im gleichen Namensraum als eines der Argumente definiert werden, die es braucht. (*)

Wenn der Compiler findet einen Funktionsaufruf, wie:

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

wird es versuchen, die f Funktion im aktuellen Namensraum (am Ort des Anrufs) oder in dem einschließenden Namespace von C1 und C2-Typen zu finden (namespace1, namespace2 :: namespace3), aber es keine andere Namespaces in der Suche.

(*) In diesem Fall sind Sie so ziemlich begrenzt auf den Test Namensraum, wie es nicht erlaubt ist, eine Funktion zu dem std-Namespace (nur Vorlage Spezialisierungen).

Ende der ursprünglichen Post .

Auch wenn so kommentiert, bevor dies nur ein Problem mit dem Compiler sein kann, ist es üblich, Nutzung und empfohlen, alle freien Funktionen zu definieren, die auf einem benutzerdefinierten Typ im gleichen Namensraum wie der Typ selbst zu betreiben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top