2010-10-06 15 views
9

Si je définis quelque part un espace de noms log et le rend accessible dans la portée globale, cela se heurtera à double log(double) à partir de l'en-tête standard cmath. En fait, la plupart des compilateurs semblent y adhérer - la plupart des versions de SunCC, MSVC, GCC - mais pas GCC 4.1.2.Comment résoudre une collision de noms entre un espace de noms C++ et une fonction globale?

Malheureusement, il n'y a aucun moyen de résoudre l'ambiguïté, car les déclarations using ne sont pas légales pour les identificateurs d'espaces de noms. Savez-vous comment je pourrais écrire log::Log dans l'espace de noms global même si cmath est inclus?

Merci.

EDIT: Quelqu'un sait-il ce que la norme C++ 03 a à dire à ce sujet? J'aurais pensé que l'opérateur de portée désambiguïsait suffisamment l'utilisation de log dans l'exemple de code ci-dessous.

#include <cmath> 

namespace foo 
{ 

namespace log 
{ 

struct Log { }; 

} // namespace log 

} // namespace foo 


using namespace foo; 

int main() 
{ 
    log::Log x; 

    return 0; 
} 

// g++ (GCC) 4.1.2 20070115 (SUSE Linux) 

// log.cpp: In function `int main()': 
// log.cpp:20: error: reference to `log' is ambiguous 
// /usr/include/bits/mathcalls.h:110: error: candidates are: double log(double) 
//  log.cpp:7: error:     namespace foo::log { } 
// log.cpp:20: error: expected `;' before `x' 
+0

Pourquoi ne pas simplement écrire comme' foo :: log :: log' pour empêcher la ambiguousity ? –

+0

'Log' n'est pas le seul membre de' foo :: log', il y en a beaucoup. Mais oui, je finirai probablement par qualifier complètement tout cela s'il n'y a pas d'autre moyen. –

+0

@cj: Vous voudrez peut-être jeter un oeil à [cette réponse] (http://stackoverflow.com/questions/2879555/c-stl-how-to-write-wrappers-for-cout-cerr-cin-and -endl/2880136 # 2880136). – sbi

Répondre

10

Je vous suggère:

foo::log::Log x; // Your logging class 
::log(0.0); // Log function 

En général, je ne voudrais pas écrire using namespace foo; car il n'y a pas de point avoir dans l'espace de noms foo si vous ne comptez pas utiliser et il pollue la espace de noms global.

Voir cette question connexe:
How do you properly use namespaces in C++?

7

Bien qu'il ne vous aide pas, l'erreur de GCC 4.1.2 est incorrecte. Le log dans log::Log peut uniquement faire référence à un nom de classe ou d'espace de noms.

Si votre code doit également compiler avec GCC 4.1.2, alors il y a deux options:

  1. Utilisez le nom complet foo::log::Log
  2. Utilisez un alias d'espace de noms:

    namespace log1 = foo::log; 
    log1::Log logger; 
+1

+1 pour l'idée d'utiliser un alias Êtes-vous sûr que l'erreur est incorrecte? Je suppose que vous voulez dire que l'opérateur de portée résout l'ambiguïté parce qu'elle ne peut pas être appliquée à un nom de fonction Je ne suis pas sûr de ce que dit la norme à propos de ce cas particulier, mais en ce qui concerne les définitions d'espace de nommage, voir section 7.3.1: "L'identificateur d'une définition d'espace de noms d'origine n'a pas été préalablement défini dans la région déclarative. -namespace-definition apparaît. " –

+1

Je suis sûr que l'erreur est incorrecte. J'ai dû chercher dans la norme, et selon la grammaire, seul un nom de classe ou d'espace de nom peut apparaître avant l'opérateur de portée. La déclaration de votre espace de noms 'log' n'est pas un problème, car elle n'est pas définie dans le même espace de noms que la fonction' log'. (l'espace de noms ne contient pas l'espace de noms 'foo', la fonction est dans l'espace de noms global) –

0

cmath utilise ::log pour une raison quelconque pour l'obtenir de la portée globale et ne peut pas décider entre la fonction et votre espace de noms.

Les espaces de noms conservent le code contenu pour empêcher confusion et pollution des signatures de fonction.

Here « sa démo complète et documentée de propernamespace utilisation:

#include <iostream> 
#include <cmath> // Uses ::log, which would be the log() here if it were not in a namespace, see https://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace 

// Silently overrides std::log 
//double log(double d) { return 420; } 

namespace uniquename { 
    using namespace std; // So we don't have to waste space on std:: when not needed. 

    double log(double d) { 
     return 42; 
    } 

    int main() { 
     cout << "Our log: " << log(4.2) << endl; 
     cout << "Standard log: " << std::log(4.2); 
     return 0; 
    } 
} 

// Global wrapper for our contained code. 
int main() { 
    return uniquename::main(); 
} 

Sortie:

Our log: 42 
Standard log: 1.43508