问题
I know the basic rules, use inline
, enum
and const
instead of #define
, that is not what I'm after with this question. What I want to know is what is considered an acceptable scenario in which you would use a #define
macro, and how, in C++.
Please do not post question or links to "define vs const" questions or "preprocessor vs compiler", and I've already gone through Effective C++ by Scott Meyers and I know the advantages of one over the other.
However after hours and hours of surfing the net, I get the feeling #define is treated as some kind of underdog in C++, but I'm sure there must be a case in which it could be acceptable, even desirable, to use it.
To get the ball rolling I guess one scenario I could think of is to create a DEBUG
macro that based on it enables prints and whatnot all over the code for debug purposes.
回答1:
Here are a few scenarios where using #define is a good solution:
Adding diagnostics information while preserving function signature:
#ifdef _DEBUG
#define Log(MSG) Log((MSG), __FILE__, __LINE__);
#endif
Conditional compilation and include guards are also a good example (no example given, as you should understand this :)).
Boilerplate code is another example, but this can easily be abused. A good example of using macros for boilerplate code is the BOOST_AUTO_TEST_CASE macro in Boost.UnitTest (a worse example is the WinAPI macro set that maps Windows APIs to their CHAR or WCHAR macros).
Another good example is providing compiler-specific keywords and settings:
#if (defined _WIN32) && (defined LIB_SHARED)
# ifdef LIB_EXPORTS
# define LIB_EXPORT __declspec(dllexport)
# else
# define LIB_EXPORT __declspec(dllimport)
# endif /* LIB_EXPORTS */
#else
# define LIB_EXPORT extern
#endif /* _WIN32 && LIB_SHARED */
Usage:
// forward declaration of API function:
LIB_EXPORT void MyFunction(int);
回答2:
The simple setup for debug/release or for crossplatform code. Here is a sample of my program:
void Painter::render()
{
if (m_needsSorting)
{
_sort();
}
for (GameObject* o : m_objects)
{
o->render();
#ifdef _DEBUG
o->renderDebug();
#endif
}
}
and one more for win/ios:
#ifdef _WIN32
#include "EGL/egl.h"
#include "GLES2/gl2.h"
#include <Windows.h>
#ifdef _ANALYZE
#include <vld.h>
#endif
#else // IOS
#import <Availability.h>
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <Foundation/Foundation.h>
#endif
the other thing is for libraries:
#ifdef VECTRY_INLINE
#define vinline inline
#else
#define vinline
#endif
and some useful stuff like this:
#define MakeShared(T) \
class T; \
typedef shared_ptr<T> T##Ptr
回答3:
One of the few usefull cases in C++ are include guards:
// A.h
#ifndef _A_H_
#define _A_H_
class A
{ /* ... */ };
#endif /* _A_H_ */
回答4:
Sometimes, you want to generate code without having to repeat the neverending boilerplate, or without having to use another language to do so. From time to time, templates will not be not enough, and you will end up using Boost.Preprocessor to generate your code.
One example where macros are "required" is Boost.TTI (type traits introspection). The underlying mechanism somehow abuses the language to create a couple of powerful metafunctions, but needs great amounts of boilerplate. For example, the macro BOOST_TTI_HAS_MEMBER_FUNCTION
generates a matefunction that checks whether a class has a given member function. Doing so requires to create a new class and cannot be short without a macro (examples of non-macro solutions to tackle the problem here).
There are also some times when you will need to use X-macros to generate your code. It is pretty useful to bind things at compile time. I am not sure whether they can be totally replaced or not as of today, but anyway, you can find some really interesting examples of applications here.
To sum up, macros can be a powerful tool to generate code, but they need to be used with caution.
回答5:
I think when C was introduced then C didn't use to have consts, so #defines
were the only way of providing constant values. But later on #define
was not much used since consts took the place(or in better words we can say that consts were more readily used). But I would say include guards is still one area where they are used. And they are used since your code is more readable.
Header inclusion guards is one area where you cannot use consts
And example:
#ifndef GRANDFATHER_H
#define GRANDFATHER_H
struct foo {
int member;
};
#endif /* GRANDFATHER_H */
You may also check Why would someone use #define to define constants?
One more thing to add that #defines
don't respect scopes so there is no way to create a class scoped namespacewhereas const variables can be scoped in classes.(I know you know the difference but thought to add it as it is important.)
Also to show one example where #define is used:
static double elapsed()
{ ... }
#define ELAPSED '[' << std::fixed << std::setprecision(2) << elapsed() << "] "
// usage:
for (vector<string>::iterator f = files.begin(); f != files.end(); f++) {
cout << ELAPSED << "reading file: " << *f << '\n';
process_file(*f);
}
来源:https://stackoverflow.com/questions/22007222/what-is-an-appropriate-use-scenario-of-define-in-c