Pergunta

Eu estou trabalhando no Visual Studio 2008 em um C ++ atribuição de programação. Nós foram fornecidos com arquivos que definem a seguinte hierarquia namespace (os nomes são apenas para a causa deste post, eu sei "namespace XYZ-NAMESPACE" é 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
      }
}

O conteúdo MAIN-namespace são divididos entre um monte de arquivos, e por alguma razão que eu não entendo o operador << para definir e LinkedList é totalmente fora da principal-namespace (mas dentro do jogo e LinkedList cabeçalho Arquivo). Aqui está a versão Set:

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

Agora, aqui está o problema: Eu tenho a seguinte estrutura de dados:

Set A
Set B
Set C
double num

É definido para estar em uma classe dentro MAIN-namespace. Quando eu criar uma instância da classe, e tente imprimir um dos conjuntos, ele me diz que: erro C2679: binary '<<': nenhum operador encontrado que leva a mão direita operando do tipo 'const MAIN-NAMESPACE :: ponteiro COLEÇÕES-NAMESPACE :: Set' (ou não há conversão aceitável)

No entanto, se eu apenas escrever uma função main (), e criar Conjunto A, preenchê-lo, e usar a operadora trabalha.

Qualquer idéia de qual é o problema? (Nota: Eu tentei qualquer combinação de usar e incluem eu poderia pensar).

Foi útil?

Solução 2

OK eu descobri isso. A intuição de jpalecek sobre lá existente outro operador << no namespace estava correta (aparentemente, eu esqueci de comentar para fora).

As regras de pesquisa para namespaces primeira partida de pesquisa no espaço de nomes da chamada de função e busca-se os espaços de nomes que encerram, até o namespace global (em seguida, ele faz a pesquisa dependente Argumento se nenhuma correspondência é encontrada). No entanto, se ao longo do caminho ele encontra alguma correspondência para o operador <<, ele pára a pesquisa, independentemente do fato de que os tipos usados ??nessas funções podem ser incompatíveis, como foi o caso aqui.

A solução é ou incluí-lo na MAIN-NAMESPACE (que eu não estou autorizado a), ou importá-lo a partir do namespace global com "usando :: operator <<".

Outras dicas

Estranho -. Mesmo que colocar funções gratuitos associados a um tipo para um namespace diferente é uma má prática, as declarações de namespace globais são sempre visíveis

A única coisa que eu posso pensar é que a declaração com o mesmo nome em MAIN-NAMESPACE iria sombra um no namespace global - não há uma operator<<, possivelmente para o tipo totalmente diferente, em MAIN-NAMESPACE? Se assim for, você deve corrigir isso por declaração using ::operator<< em MAIN-NAMESPACE. Exemplo:

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

Tente chamar a função explicitamente?

::operator<<( cout, myObj );

Como SoaBox apontou, tente chamá-lo explicitamente.

Para sua informação, se você quiser chamar uma função global que tem sido escondida no namespace atual preceder a função com :: Para ignorar a função local e chamar a função global.

Tente chamar a função explicitamente?

:: operator << (cout, myObj);

Sim, isso funciona!

que irá tentar encontrar a função f em o namespace atual (no local de chamar) ou nos espaços de nomes que encerram de C1 e C2 tipos (namespace1, namespace2 :: namespace3), mas vai não tentar outros namespaces no pesquisar.

Então, vamos ver se eu entendi direito: a razão invocando o operador << de uma função main () trabalhou é porque eu estava no espaço global (como era operador <<). A razão que falhou ao invocar a partir da classe I implementada é porque a classe estava em um namespace não global e não havia variáveis ??em que apontavam o compilador para o namespace global.

pessoas OK perguntou por exemplos específicos, então aqui está a parte relevante do código. // Disclamer: no caso de alguém magro do meu uni vê isso, a encontra no arquivo de submissão, e decide Copiei-lo ou algo assim, o meu número de estudante é 311670137

Esta é a Set.h arquivo de cabeçalho:

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

Este é o que eu definido em um arquivo 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;
    };

}

E aqui está do principal:

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

reportRegisteredStations é definido como:

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

        outputStream<<places;
    }

Isso funciona para mim

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

CORREÇÃO : O texto abaixo é baseado na experiência com a família g ++ de compiladores. Após o comentário para a resposta reli o padrão (que afirma que ADL serão utilizados mais de pesquisa de nome regular, e pesquisa de nome regular deve encontrar o operador <<). Eu também tentei com comeau compilador (o compilador compatível com padrão mais eu saiba) eo símbolo é encontrado. Parece um problema com g ++ (versões tentaram 3.3, 4.1, 4.3).

resposta Original:

Pesquise Koening lookup (tecnicamente ADL: Argumento de pesquisa dependente).

A resposta curta é que se você tem a seguinte classe:

namespace test {
    class A {};
}

o operador de inserção de fluxo deve ser definida como:

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

Funções ou operadores devem ser definidos no mesmo namespace como um dos argumentos que ele leva. (*)

Quando o compilador encontra uma chamada de função, tais como:

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

ele vai tentar encontrar o f função no namespace atual (no local de chamada) ou nos namespaces que encerram de C1 e C2 tipos (namespace1, namespace2 :: namespace3), mas não tentar outros namespaces na pesquisa.

(*) Neste caso, você está praticamente limitado ao test namespace, como você não tem permissão para adicionar uma função para o namespace std (apenas especializações modelo).

End of post original .

Mesmo como comentado antes que este pode ser apenas um problema com o compilador, é de uso comum e recomendado para definir todas as funções livres que operam em um tipo definido pelo utilizador no mesmo espaço de nomes como o próprio tipo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top