2009-04-02 6 views
2

Je continue d'apprendre le C++, et je n'ai jamais vraiment créé mes propres espaces de noms auparavant. J'expérimentais avec eux et même si j'ai beaucoup de choses à faire, il y a une chose que je n'arrive toujours pas à faire. Je voudrais être en mesure d'appeler une méthode statique dans une classe sans taper quelque chose comme NameOfClass::method. Voici ce que je pensais que le code doit ressembler, mais il ne peut pas compiler:C++ en utilisant des espaces de noms pour éviter les longs chemins

fichier A.h,

namespace Test 
{ 
    class A 
    { 
     public: 
      static int foo() { return 42; } 
    }; 
} 

fichier main.cpp,

#include <iostream> 

#include "A.h" 

using namespace std; 
using namespace Test::A; 

int main() 
{ 
    cout << foo() << endl; 

    return 0; 
} 

Le compilateur me donne:

main.cpp:6: error: ‘A’ is not a namespace-name 
main.cpp:6: error: expected namespace-name before ‘;’ token 
main.cpp: In function ‘int main()’: 
main.cpp:10: error: ‘foo’ was not declared in this scope 

Est-il possible de faire ce que j'essaye de faire sans taper A::foo?

Répondre

5

Il n'y a aucun moyen de contourner cela, vous devez spécifier le nom de classe pour les méthodes statiques.

using namespace Test; 

Puis:

int answerToEverything = A::foo(); 
+0

C'est un bummer. : -/ –

0

Non, il est impossible de faire ce que vous essayez de faire de toute façon élégante. La chose la plus proche que vous serez capable de faire est de créer une macro ou une fonction inline qui délègue à votre fonction. Cependant, ces deux alternatives sont plutôt moche, donc je ne vais pas publier d'échantillons de code. Mordez la balle et spécifiez le nom entier, ou refactorisez votre code pour que les méthodes statiques ne soient que des fonctions globales.

10

En C++, vous/particulièrement/devez lire attentivement les messages d'erreur du compilateur.

Notez que la première erreur était "error: 'A' n'est pas un nom d'espace de noms". C'est vrai, A est un nom de classe.

using namespace Foo; // brings in all of foo; 
using Bar::Baz // brings in only Baz from Bar 

Vous voulez écrire:

using Test::A; 

Cela fait deux bonnes choses: il apporte un pour vous d'utiliser, et il ne met pas tout le reste du test, ce qui est bon aussi, parce que vous ne devez apporter que ce dont vous avez besoin, afin de ne pas dépendre accidentellement de quelque chose dont vous ne réalisez pas que vous dépendez. Cependant, comme foo est statique dans A, vous devrez toujours vous référer à A :: foo explicitement. (A moins que vous ne fassiez quelque chose comme écrire une fonction gratuite qui redirige vers A :: foo, en général, c'est une mauvaise idée si vous ne faites que sauvegarder une frappe.)

Certains peuvent vous conseiller de ne pas utiliser les déclarations du tout, au lieu de qualifier pleinement tous les noms. Mais ceci est (pour citer Stroustrup) "fastidieux et sujet aux erreurs", et cela entrave le refactoring: disons que vous qualifiez pleinement chaque utilisation de la classe FooMatic :: Stack, et que la direction insiste juste avant Vous allez utiliser la classe Stack de BarMatic, car barMatic vient de racheter votre entreprise.

Si vous étiez pleinement qualifié partout, vous feriez beaucoup de grepping, en espérant que votre regex avait raison. Si vous avez utilisé une déclaration using, vous pouvez simplement corriger votre fichier d'en-tête (que nous espérons partagé).De cette façon, une déclaration using est un peu comme un "typedef int ourInt;" ou une constante manifeste ou const: "const int FOO = 1;", en ce qu'elle fournit un endroit pour changer quelque chose qui est référé à de nombreux endroits. En qualifiant pleinement un espace de noms à chaque utilisation, vous perdez cet avantage. Inversement, si vous aviez utilisé une directive using et introduit tout Namespace FooMatic, votre grep aurait pu être encore plus dur, si la direction insistait sur BarMatic :: Foo mais que vous deviez utiliser FooMatic: Baz, l'équivalent BarMatic pour Baz étant pour une raison quelconque inutilisable. Apporter un type (classe, fonction, constante) à la fois est généralement le plus flexible, la meilleure façon de se protéger contre des changements inévitables mais encore inconnus. Comme dans la plupart des codages, vous voulez minimiser les répétitions fastidieuses tout en conservant une granularité suffisante.

+0

Je crois que vous voulez dire, "vous devez TOUJOURS lire attentivement les messages d'erreur du compilateur". – Tom

+0

Il y a beaucoup d'outils qui peuvent faire du refactoring. pas d'expressions régulières nécessaires. Je n'utilise presque jamais la déclaration 'using' car elle pollue l'espace de noms global, ce qui est un pire problème à mon avis. Le refactoring est pratiquement un non-problème. –

0

Ne pas utiliser un abuseur d'espace de nom. Utilisez ces espaces de noms!

std::cout << Test::A::foo() << std::endl; 
Questions connexes