Domanda

Sto lavorando in Visual Studio 2008 su un incarico di programmazione C ++. Ci sono stati forniti file che definiscono la seguente gerarchia dello spazio dei nomi (i nomi sono solo per il bene di questo post, lo so & Quot; namespace XYZ-NAMESPACE & Quot; è ridondante):

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

I contenuti di MAIN-NAMESPACE sono divisi tra un mucchio di file, e per qualche ragione non capisco l'operatore < < sia per Set che per LinkedList è completamente esterno a MAIN-NAMESPACE (ma all'interno del file di intestazione di Set e LinkedList). Ecco la versione impostata:

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

Ora ecco il problema: ho la seguente struttura di dati:

Set A
Set B
Set C
double num

È definito per essere in una classe all'interno di MAIN-NAMESPACE. Quando creo un'istanza della classe e provo a stampare uno dei set, mi dice che: errore C2679: binario '< <' : nessun operatore trovato che accetta un operando di destra di tipo "const MAIN-NAMESPACE :: POINTER-COLLECTIONS-NAMESPACE :: Set" (o non vi è alcuna conversione accettabile)

Tuttavia, se scrivo solo una funzione main () e creo il Set A, lo riempio e uso l'operatore, funziona.

Qualche idea su quale sia il problema? (nota: ho provato qualsiasi combinazione di utilizzo e inclusione mi venisse in mente).

È stato utile?

Soluzione 2

OK, l'ho capito. l'intuizione di jpalecek sull'esistenza di un altro operatore < < nello spazio dei nomi era corretto (apparentemente mi ero dimenticato di commentarlo).

Le regole di ricerca per gli spazi dei nomi avviano innanzitutto la ricerca nello spazio dei nomi della chiamata di funzione e cercano gli spazi dei nomi racchiusi, fino allo spazio dei nomi globale (quindi esegue la ricerca dipendente dall'argomento se non viene trovata alcuna corrispondenza). Tuttavia, se lungo la strada trova una corrispondenza per l'operatore & Lt; & Lt ;, interrompe la ricerca, indipendentemente dal fatto che i tipi utilizzati in tali funzioni possano essere incompatibili, come nel caso qui.

La soluzione è di includerlo in MAIN-NAMESPACE (cosa che non mi è permesso), o importarlo dallo spazio dei nomi globale con " using :: operator < < " ;.

Altri suggerimenti

Strano - anche se mettere funzioni libere associate a un tipo in un diverso spazio dei nomi è una cattiva pratica, le dichiarazioni globali dello spazio dei nomi sono sempre visibili.

L'unica cosa che mi viene in mente è che la dichiarazione con lo stesso nome in MAIN-NAMESPACE oscurerebbe quella nello spazio dei nomi globale - non c'è un operator<<, possibilmente per un tipo totalmente non correlato, in using ::operator<<? In tal caso, è necessario correggerlo mediante la <=> dichiarazione in <=>. Esempio:

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

Prova a chiamare esplicitamente la funzione?

::operator<<( cout, myObj );

Come sottolineato da SoaBox, prova a chiamarlo esplicitamente.

Per tua informazione, se desideri chiamare una funzione globale che è stata nascosta nello spazio dei nomi corrente precedere la funzione con :: per bypassare la funzione locale e chiamare la funzione globale.

  

Prova a chiamare esplicitamente la funzione?

     

:: operator < < (cout, myObj);

Sì, funziona!

  

proverà a trovare la funzione f in   lo spazio dei nomi corrente (al posto di   call) o negli spazi dei nomi allegati   di tipi c1 e c2 (namespace1,   namespace2 :: namespace3), ma lo farà   non provare altri spazi dei nomi in   ricerca.

Quindi vediamo se ho capito bene: la ragione per invocare l'operatore < < da una funzione main () ha funzionato perché ero nello spazio dei nomi globale (come lo era l'operatore < <). Il motivo per cui ha fallito quando si invoca dalla classe che ho implementato è perché la classe si trovava in uno spazio dei nomi non globale e non c'erano variabili che indicavano il compilatore verso lo spazio dei nomi globale.

OK, le persone hanno chiesto esempi specifici, quindi ecco la parte pertinente del codice. // Disclamer: nel caso sottile qualcuno della mia uni vede questo, lo incontra nel file di presentazione e decide che l'ho copiato o qualcosa del genere, il mio numero di studente è 311670137

Questo è il file di intestazione 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;
}

Questo è ciò che ho definito in un altro file:

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

}

Ed ecco il principale:

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

reportRegisteredStations è definito come:

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

        outputStream<<places;
    }

Questo funziona per me

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

CORREZIONE : il testo seguente si basa sull'esperienza con la famiglia di compilatori g ++. Dopo il commento alla risposta, ho riletto lo standard (che afferma che ADL verrà utilizzato per la normale ricerca dei nomi, e la normale ricerca dei nomi dovrebbe trovare l'operatore & Lt; & Lt;). Ho anche provato con il compilatore comeau (il compilatore conforme più standard che conosco) e il simbolo è stato trovato. Sembra un problema con g ++ (versioni provate 3.3, 4.1, 4.3).

Risposta originale:

Cerca la ricerca Koening (tecnicamente ADL: ricerca dipendente dall'argomento).

La risposta breve è che se hai la seguente classe:

namespace test {
    class A {};
}

l'operatore di inserimento stream deve essere definito come:

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

Le funzioni o gli operatori devono essere definiti nello stesso spazio dei nomi di uno degli argomenti che accetta. (*)

Quando il compilatore trova una chiamata di funzione come:

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

tenterà di trovare la funzione f nello spazio dei nomi corrente (nel luogo della chiamata) o negli spazi dei nomi racchiusi dei tipi c1 e c2 (namespace1, namespace2 :: namespace3), ma esso non tenterà altri spazi dei nomi nella ricerca.

(*) In questo caso, sei praticamente limitato allo spazio dei nomi test , poiché non ti è permesso aggiungere una funzione allo spazio dei nomi std (solo specializzazioni di template).

Fine del post originale .

Anche se, come commentato prima, questo potrebbe essere solo un problema con il compilatore, è un uso comune e si consiglia di definire tutte le funzioni gratuite che operano su un tipo definito dall'utente nello stesso spazio dei nomi del tipo stesso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top