41

My application uses another output than the standard output for logging information, which is why I wrote my own Log(), Error(), Panic() and Assert() functions. To organize things nicely, I enclose all the debugging stuff in a Debug namespace.

It would make more sense for the Assert() function to also provide a source file and line number, which is only possible using the __LINE__ and __FILE__ macros. However, it is pretty unpleasant, inefficient etc... to always have to specify these two parameters.

So this is how my code would look like:

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

My question is, is it possible to place a macro which includes those two parameters inside the Debug namespace? Like this:

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

Is this valid c++? If not, is there any way of making this work?

Tibi
  • 4,015
  • 8
  • 40
  • 64
  • 3
    This will work, but the macro is not part of the namespace. – Paul R Aug 03 '12 at 07:34
  • 1
    @PaulR So in other words, if I omit `Debug::`, the macro would still work? – Tibi Aug 03 '12 at 07:39
  • 4
    No - you still need the namespace prefix (because all you're doing is translating `Assert` to `Assert_` in the preprocessor) - the problem is that if you use `Assert` outside the namespace then it will still get translated, which is probably not be what you want to happen. – Paul R Aug 03 '12 at 07:51

5 Answers5

58

Is it possible to place a macro in a namespace in c++?

No.

#define is a preprocessor directive. The macros are being replaced before anything else apart from removing comments (which means, before compilation). So at the time macros are replaced, the compiler knows nothing about your namespaces.

As other people state, in your case it will be fine. However, This is how you can get problems:

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

So while it looks like the defines are "in the namespaces", they are not, and the last #define will be always be used, which in this case will lead to a compile-time error, because the code in main will be replaced by:

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

instead of

A::Assert(0,"asdasd", _FILE_, _LINE_);
B::Assert(0);
Foggzie
  • 9,691
  • 1
  • 31
  • 48
SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
  • 3
    @Tibi - the way is not to use `macro`s. Use constants or inline functions, defined in your namespace. – Kiril Kirov Aug 03 '12 at 07:30
  • 1
    Why wouldn't it work. `Assert` would expand to `Assert_` with the extra 2 parameters. What's the problem? – Luchian Grigore Aug 03 '12 at 07:31
  • @LuchianGrigore - the "problem" is in the titme: "Is it possible to place a macro in a namespace in c++?" – Kiril Kirov Aug 03 '12 at 07:32
  • @KirilKirov You lost me there a little bit. How can I use constants and inline functions to get the line and source file when the function is called? – Tibi Aug 03 '12 at 07:32
  • @KirilKirov I don't see how that's a problem. You can put macros anywhere. – Luchian Grigore Aug 03 '12 at 07:33
  • @LuchianGrigore - true, you can. Maybe I understand the question a little different. – Kiril Kirov Aug 03 '12 at 07:34
  • @Tibi - LuchianGrigore is right, I just thought you want to "restrict" the access to this macro only for this namespace, or only by explicitly specifying the namespace, it's defined in. – Kiril Kirov Aug 03 '12 at 07:37
  • I have. You're saying re-defining a macro leads to trouble. True. A lot of things, when misused, can lead to trouble... If you re-define `assert` in your own code, to take 10 parameters, you'd also get errors. – Luchian Grigore Aug 03 '12 at 07:42
  • I removed the downvote, but I suggest you don't start your answer with "No", as it certainly is possible. – Luchian Grigore Aug 03 '12 at 07:45
  • @LuchianGrigore, yes. I just wanted to point out that the macros are not _in namespaces_. If you use `A::someFunction()`, you expect a function from `A` namespace to be called. You can't expect the same from macros, and that's how I understood the OP's question. – SingerOfTheFall Aug 03 '12 at 07:45
  • @LuchianGrigore, `I suggest you don't start your answer with "No"`, yes, that's a good point for any answer I guess :P thx. – SingerOfTheFall Aug 03 '12 at 07:48
2

No, the preprocessor doesn't care about namespaces at all. In fact, the preprocessor runs, at least conceptually, before the compiler sees anything.

For myself, I just do a standard ASSERT macro, and expect that no "sane namespace" has something called ASSERT. Problem solved. Should I require a library that has an ASSERT of its own then I can still decide how to deal with this; however, the only library that I'm currently using with its own "assert" calls it BOOST_ASSERT or something like that...

Christian Stieber
  • 9,954
  • 24
  • 23
2
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"); 

This specific usage would do exactly what you want, but the Assert macro is in no way part of the Debug namespace... it's exactly as if you'd done:

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

Here, the substitution works not because Assert was in the Debug namespace (it's not in your code or this code, and the preprocessor has no clue what namespaces are about) - it works because Assert is recognised as an identifier for a macro, the substitution of Assert_ is made, then later the compiler proper happens to find there's a Debug::Assert_ So, say you have somewhere later in your translation unit you have some completely unrelated code:

my_object.Assert(my_functor);

The macro substituion will still kick in to produce a compile-time error saying you have the wrong number of arguments to a macro. Say the unrelated code was instead:

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

Then that would be replaced with:

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

(Separately, it's standard practice not to use lower case letters in preprocessor macro names).

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • `Separately, it's standard practice not to use lower case letters in preprocessor macro names`. I know, but take the windows api for example. There are many macros that don't respect this practice, so that they call the ascii/unicode version of another function. – Tibi Aug 03 '12 at 09:32
0

You can try __PRETTY_FUNCTION __ macro to print all the namespaces including function arguments.

  • 2
    While this might be a valuable hint to solve the problem, an answer really needs to demonstrate the solution. Please [edit] to provide example code to show what you mean. Alternatively, consider writing this as a comment instead. – Toby Speight Nov 10 '16 at 16:12
-2

Yes, and your macro would expand to exactly what you expect.

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

would be replaced by

Debug::Assert_(some_condition, "Some_condition should be true", __FILE__, __LINE__)
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625