compilador C ++ incapaz de encontrar a função (namespace relacionado)
-
20-08-2019 - |
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).
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.