Question Est-il possible de placer une macro dans un espace de noms en c ++?


Mon application utilise une autre sortie que la sortie standard pour enregistrer les informations, raison pour laquelle j'ai écrit la mienne Log(), Error(), Panic() et Assert() les fonctions. Pour bien organiser les choses, je joins tous les éléments de débogage dans un Debug espace de noms.

Il serait plus judicieux pour le Assert() fonction de fournir également un fichier source et un numéro de ligne, ce qui est uniquement possible en utilisant le __LINE__ et __FILE__ macros. Cependant, il est assez désagréable, inefficace, etc. de toujours avoir à spécifier ces deux paramètres.

Voici comment mon code ressemblerait:

namespace Debug {
   void Assert (int condition, std::string message, std::string file, int line);
}

Ma question est, est-il possible de placer une macro qui inclut ces deux paramètres dans le Debug espace de nommage? Comme ça:

namespace Debug {
   void Assert_ (int condition, std::string message, std::string file, int line);
   #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)
}

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true");

// Output: Assertion failed on line 10 in file test.cpp:
//           Some_condition should be true

Est-ce que c ++ est valide? Sinon, existe-t-il un moyen de faire ce travail?


16
2017-08-03 07:27


origine


Réponses:


#define est une directive de préprocesseur. Les macros sont en cours de remplacement avant autre chose que la suppression des commentaires (ce qui signifie avant la compilation). Donc, au moment où les macros sont remplacées, le compilateur ne sait rien de vos espaces de noms.

Comme d'autres personnes le disent, ce sera bien dans votre cas. Cependant, voici comment vous pouvez avoir des problèmes:

namespace A
{
 void Assert_ (int condition, std::string message, std::string file, int line)
 {
     std::cout << "A";
 }
   #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)

}
namespace B
{
 void Assert_ (int condition)
 {
     std::cout << "B";
 }
   #define Assert(a,b) Assert_(a)

}

int main(int argc, char *argv[])
{
    A::Assert(0,"asdasd");
    B::Assert(0,"asdasd");
}

Donc, alors que les définitions sont "dans les espaces de noms", elles sont ne pas, et le dernier #define sera toujours utilisé, ce qui dans ce cas conduira à une erreur de compilation, car le code dans main sera remplacé par:

A::Assert(0);
B::Assert(0);

au lieu de

A::Assert(0,"asdasd", _FILE_, _LINE_);
B::Assert(0);

26
2017-08-03 07:28



namespace Debug
{
    void Assert_(int condition, std::string message, std::string file, int line);
    #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)
}

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true"); 

Cet usage spécifique ferait exactement ce que vous voulez, mais la macro Assert ne fait en aucun cas partie de l'espace de noms Debug... c'est exactement comme si vous aviez fait:

namespace Debug
{
    void Assert_(int condition, std::string message, std::string file, int line);
}

#define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true"); 

Ici, la substitution ne fonctionne pas parce que Assert était dans le Debug namespace (ce n'est pas dans votre code ou ce code, et le préprocesseur n'a aucune idée de ce que sont les espaces de noms) - cela fonctionne parce que Assert est reconnu comme identifiant pour une macro, la substitution de Assert_ est faite, puis plus tard, le compilateur proprement dit arrive à trouver un Debug::Assert_ Donc, disons que vous avez quelque part plus tard dans votre unité de traduction, vous avez un code complètement indépendant:

my_object.Assert(my_functor);

La substitution de macro va quand même produire une erreur de compilation indiquant que vous avez un nombre incorrect d'arguments dans une macro. Disons que le code non apparenté était à la place:

my_object.Assert(my_functor, "some text");

Ensuite, cela serait remplacé par:

my_object.Assert_(my_functor, "some text", __FILE__, __LINE__);

(Séparément, il est pratique courante de ne pas utiliser de lettres minuscules dans les noms de macro de préprocesseur).


2
2017-08-03 08:05



Non, le préprocesseur ne se soucie pas du tout des espaces de noms. En fait, le préprocesseur s'exécute, au moins conceptuellement, avant que le compilateur ne voit quelque chose.

Pour ma part, je fais juste une macro ASSERT standard et je m'attends à ce qu'aucun "espace de noms sain" n'ait quelque chose appelé ASSERT. Problème résolu. Devrais-je avoir besoin d'une bibliothèque avec un ASSERT propre alors je peux encore décider comment traiter cela; Cependant, la seule bibliothèque que j'utilise actuellement avec ses propres "assert" l'appelle BOOST_ASSERT ou quelque chose comme ça ...


1
2017-08-03 07:32



Oui, et votre macro serait exactement ce que vous attendez.

Debug::Assert (some_condition, "Some_condition should be true");

serait remplacé par

Debug::Assert_(some_condition, "Some_condition should be true", __FILE__, __LINE__)

0
2017-08-03 07:30



Vous pouvez essayer __PRETTY_FUNCTION __ macro pour imprimer tous les espaces de noms, y compris les arguments de fonction.


0
2017-11-10 02:03