Sign in to follow this  

C++ Alternatives to #define'd macros...

This topic is 3739 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi All, I've seen in the forum recently some comments to the effect that there is really no effective replacement for C's #define'd macros in C++. What about (1) inlined functions, (2) templated inline functions or (2) unnamed namespace function pointers (like macros but limited to translation unit)? Would these be as effective? And which would be the most effecive? The opinions are that with #define'd macros, the preprocessor will always insert the macro, whereas with inline sometimes this will be done and sometimes not, depending upon the compiler. Is this true? --random

Share this post


Link to post
Share on other sites
The "inline" keyword is just a suggestion. The compiler can choose to not inline if it really wants to.

I've found some places where a macro is appropriate. When checking for errors, I need to check a return value and return from the function if it is an error. I then log the line number and source code filename (using __LINE__ and __FILE__).

Making it a macro means that I don't have to write out a comparison every time I want to check a return code, and using a macro means I can use __LINE__ and __FILE__ to log errors.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
The "inline" keyword is just a suggestion. The compiler can choose to not inline if it really wants to.

True enough, but then again the compiler usually knows well enough when it's advatageious. This is not an argument for using preprocessor macros over inline functions, it's merely a statement of (irrelevant) fact.
Quote:
I've found some places where a macro is appropriate. When checking for errors, I need to check a return value and return from the function if it is an error. I then log the line number and source code filename (using __LINE__ and __FILE__).

Making it a macro means that I don't have to write out a comparison every time I want to check a return code, and using a macro means I can use __LINE__ and __FILE__ to log errors.

I'm not seeing an argument in favour of preprocesor macros over inline functions. I'm just seeing a statement that you prefer C-with-classes over idiomatic C++.

There are two ways you can do what you want in idiomatic C++, neither of which requires any more from the preprocess than using __FILE__ and __LINE__ (something which I've found over time has very little utility but seems like a good idea at the time).

(1) Use an inline function returning a bool and taking your status value and __FILE__ and __LINE__ as arguemnts. If the function returns false, return. It's no worse than hiding a goto in a preprocessor macro (which you are effectively doing now, and trust me, future maintenance programmers will direct wrath upon you for doing that).

(2) Throw an exception. Construct the exception with __FILE__ and __LINE__ as arguments. Yeah, you have to type in the comparison every time you have to compare the return code, but it's explicit and that's a Very Good Thing.

There are so many aguments against preprocessor macro functions and in favour of writing C++ code instead that there is really no excuse to use the preprocessor for anything except platform feature #ifdefs and externally-defined values passed on the compiler command line.

--smw

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma
Quote:
Original post by Sc4Freak
The "inline" keyword is just a suggestion. The compiler can choose to not inline if it really wants to.

True enough, but then again the compiler usually knows well enough when it's advatageious. This is not an argument for using preprocessor macros over inline functions, it's merely a statement of (irrelevant) fact.
Quote:
I've found some places where a macro is appropriate. When checking for errors, I need to check a return value and return from the function if it is an error. I then log the line number and source code filename (using __LINE__ and __FILE__).

Making it a macro means that I don't have to write out a comparison every time I want to check a return code, and using a macro means I can use __LINE__ and __FILE__ to log errors.

I'm not seeing an argument in favour of preprocesor macros over inline functions. I'm just seeing a statement that you prefer C-with-classes over idiomatic C++.

There are two ways you can do what you want in idiomatic C++, neither of which requires any more from the preprocess than using __FILE__ and __LINE__ (something which I've found over time has very little utility but seems like a good idea at the time).

(1) Use an inline function returning a bool and taking your status value and __FILE__ and __LINE__ as arguemnts. If the function returns false, return. It's no worse than hiding a goto in a preprocessor macro (which you are effectively doing now, and trust me, future maintenance programmers will direct wrath upon you for doing that).

(2) Throw an exception. Construct the exception with __FILE__ and __LINE__ as arguments. Yeah, you have to type in the comparison every time you have to compare the return code, but it's explicit and that's a Very Good Thing.

There are so many aguments against preprocessor macro functions and in favour of writing C++ code instead that there is really no excuse to use the preprocessor for anything except platform feature #ifdefs and externally-defined values passed on the compiler command line.

--smw


I guess that he meant using __FILE__ and __LINE__ of the caller, which varies from call to call. Making a small macro that propagates these values into 2 extra parameters (e.g. LOG(...) expanding to my_log_func(...,__FILE__,__LINE__)) is the only use I've ever really made of macros, and I don't even do that any more.

Share this post


Link to post
Share on other sites
Quote:

I've seen in the forum recently some comments to the effect that there is really no effective replacement for C's #define'd macros in C++. What about (1) inlined functions, (2) templated inline functions or (2) unnamed namespace function pointers (like macros but limited to translation unit)? Would these be as effective? And which would be the most effecive?

There is no effective replacement for #define. inline functions cannot be used for preprocessor gating (a la header guards), for one. Although you specified macros, specifically, but you still have the issue of not being able to do token stringification (#symbol) or token concatenation (a##b) with inline functions.

Of course, situations where these are required and/or good practice not common.

Share this post


Link to post
Share on other sites
Quote:
Original post by random_thinker
I've seen in the forum recently some comments to the effect that there is really no effective replacement for C's #define'd macros in C++. What about (1) inlined functions, (2) templated inline functions or (2) unnamed namespace function pointers (like macros but limited to translation unit)? Would these be as effective? And which would be the most effecive?


Effective for what?

Depending on what you need to do, preprocessor macros might or might not be the best tools. However, it's generally accepted that if the macro acts semantically as a function, then a function should be used for performance reasons and if the macro does something unusual to the control flow of the calling function (such as containing a return statement), then it should not be used at all.

Preprocessor macros are still useful for build-time configuration, conditional compilation (such as assertions) and that's about it. Other usages (such as determining the stack layout) can be done, but it involves higher maintenance and one should generally prefer using a scripting language with the relevant amount of introspection instead.

Share this post


Link to post
Share on other sites
Quote:
I've seen in the forum recently some comments to the effect that there is really no effective replacement for C's #define'd macros in C++. What about (1) inlined functions, (2) templated inline functions or (2) unnamed namespace function pointers (like macros but limited to translation unit)? Would these be as effective? And which would be the most effecive?


Yes, there's no replacement for those, because those lead to problems and are clear demonstration of C mentality and all related disasters.

C++ compilers are complex beasts which resent being led by hand.

For C++, write the code. The compiler will be several times smarter than you as to what and how to inline, optimize or even remove.

Using macros for functions in C++ borders on blasphemy. Unlike C, which is stuck in stone age due to so many legacy rules, C++ compilers have gone a long way. If this is even hinting at optimization, then forget about it. There's zero performance to be gained through macros used this way.

If you want conditional selection of functions, then templates are the way to go.

Share this post


Link to post
Share on other sites
Thx All,

Personally, I've never had any speed or efficiency problems with small inlined templates...in fact they typically do their work with blazing speed under my setup, which is GCC v. 4+. I am personally against the use of #define'd macros, it just seems to break the whole strongly typed basis of C++ code.

--random

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
Of course, situations where these are required and/or good practice not common.


As has been mentioned, the only place I use them is for logging unexpected failures as a describe in Chapter 1. Introduction of my book. I'll use a macro to provide __FILE__, __LINE__ and a string-ified version of the failing expression. Having all of these in your logging system makes it trivial to find the source of the error because the log tells you exactly which file on which line and which expression failed. There isn't any inline function equivalent for that. Of course the macro just supplies the string-ified expression, __FILE__ and __LINE__ to an inline function that does the real work, but having a macro eliminates lots of duplicated instrumentation that would otherwise just go stale.

There are times when an aggregate initializer to an array of structures with many repeated field values from one structure to the next that its handy to have a macro to eliminate the duplication. You could write an inline function to return the structure, but I find that writing a macro is no more offensive. I generally #undef the macro after the aggregate initializer if that's the only place I use it, and I don't put such aggregate initializers in .h files, only in .cpp files.

This one situation (getting caller context) is the only place left where macros are needed in my C++ work; the aggregate initializer business could be done with inline functions but feels unnecessarily complex.

Share this post


Link to post
Share on other sites
Macros *are* powerful. They can considerably reduce code verbosity (in a good way), however, C implements a horrid macro system. This means that you shouldn't usually use it, but there are cases where it can be really helpful.

Just look at Lisp/Scheme, where a macro system is properly implemented. Just thought I'd throw in my defense for macros, although probably off topic since we're talking about C++.

Share this post


Link to post
Share on other sites
Quote:
Original post by okonomiyaki
Macros *are* powerful. They can considerably reduce code verbosity (in a good way), however, C implements a horrid macro system. This means that you shouldn't usually use it, but there are cases where it can be really helpful.

Just look at Lisp/Scheme, where a macro system is properly implemented. Just thought I'd throw in my defense for macros, although probably off topic since we're talking about C++.


I don't think it's off topic in the context of C++, macros can and commonly are used for code generation in C++, which I think is a valid use provided it's restricted to the internal implementation of a library. This is why Boost.Preprocessor exists after all.

Share this post


Link to post
Share on other sites

This topic is 3739 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this