| #define directive |
#define identifier definition |
The #define directive defines a macro named
identifier. The macro''s
replacement text is the list of tokens shown as
definition. The macro can be simple, with
no arguments, or can have an argument list. The argument list is
introduced by a left parenthesis that immediately follows the macro
name. If there is a space between
identifier and (, the
( is interpreted as the start of the definition of
a simple macro. The identifier-list can be
empty, or it can be a list of identifiers separated by commas.
Whitespace is permitted in the
identifier-list and before the closing
parenthesis.C programmers are accustomed to using macros to declare constants and
simple inline functions, but C++ offers const
declarations, true inline functions, and templates. Macros are
therefore used much less often in C++ than in C. The main drawback to
macros is that they do not obey scope or
namespace rules. When you must use macros, a common convention is to
use all uppercase letters for the macro names, and never use all
uppercase letters for non-macro names.A
macro''s
scope is from the point of definition to the end of the source file,
or until you undefine the macro with the
#undef
directive. If you try to repeat a macro definition, the new
definition must be identical to the original definition. The only way
to give a macro a different definition is to undefine it first.
definition, it is replaced with the replacement text. Macro names are
not replaced inside string and character literals, however. The
replacement text is rescanned for macro names, which are recursively
expanded until no more replacements take place. During replacement,
the original macro name is not expanded if it appears in any
replacement text. Here is a simple example of a macro definition and
use:
#define NAME "NAME = Tempest Software, Inc."During the macro expansion phase of
char companyName[] = NAME;
compilation, the token NAME will be replaced by
its expansion, with the following result:
char companyName[] = "NAME = Tempest Software, Inc.";The replacement text is never interpreted as a preprocessing
directive. This means, for example, you cannot
#define a macro within a macro''s
replacement text. Also, directive names are not subject to macro
replacement (although directive arguments are).You can also declare a macro with a parameter list, which is
sometimes called a function-like
macro:
#define DECLARE(x,y, z) x y = zTo use a function-like macro, the macro name must be followed by a
#define PRINT(a) (::std::cout << (a) << ''\n'')
comma-separated argument list in parentheses. A single argument can
contain balanced parentheses, and within those parentheses, you can
have commas, which are not interpreted as argument separators. The
macro invocation must have the same number of arguments as the macro
definition has parameters. Newlines are permitted as ordinary
whitespace characters in a macro invocation.The following example uses the DECLARE and
PRINT macros defined in the previous example:
int main( )In the macro replacement text, each occurrence of a parameter name is
{
DECLARE(int, x, 42);
PRINT((x = 10, x+2));
}
replaced by the corresponding argument. For example, the macro
expansion for the previous example results in the following:
int main( )You must be extra cautious when using a template instantiation as a
{
int x = 42;
(::std::cout << (x = 10, x + 2) << ''\n'');
}
macro argument. The angle brackets that surround the template
arguments are not treated specially for macro arguments, so commas
that separate the template arguments are interpreted as separators
for the macro arguments. In the following example, the
DECL macro attempts to declare an object named
n with type t. This works fine
for a simple type, such as int, but fails with a
template instantiation. When used with
map<int,int>, the comma separates macro
arguments, so the preprocessor sees three macro
argumentsstd::map<int,
int>, and mand
reports an error:
#define DECL(t, n) t n = t( )When a macro is expanded, the macro arguments are expanded, and each
DECL(int, zero); // Expands to int zero = int( )
DECL(std::map<int,int>, m); // Error
parameter is replaced by its corresponding expanded argument unless
the parameter is an operand to the # or
## operator. After the arguments have been
expanded, the # and ##
operators are evaluated, and the resulting text is rescanned for
macros. The macro name is expanded only once, so rescanning does not
expand the name of the macro being expanded.
Predefined Macros
The following
macros
are predefined. Do not undefine or redefine any of the predefined
macros.
- _ _cplusplus
Has the value 199711L. Future versions of the C++
standard will use a larger value. Nonconforming compilers should use
a different value.
_ _DATE_ _
Expands to the date of compilation, as a string literal, in the form
"Mmm dd yyyy", in which
dd begins with a space for numbers less than 10.
An implementation is free to substitute a different date, but the
form is always the same, and the date is always valid.- _ _FILE_ _
Expands to the name, as a string literal, of the source file being
compiled.- _ _LINE_ _
Expands to the line number, as a decimal constant, of the source file
being compiled.
_ _STDC_ _
Is implementation-defined. C++ compilers might define this macro; if
it is defined, the value is implementation-defined. Note that C
compilers are required to define _ _STDC_ _ as
1, and in some implementations, the same
preprocessor might be used for C and C++.
_ _TIME_ _
Expands to the compilation time, as a string literal, in the form
"hh:mm:ss". An implementation is free to
substitute a different time, but the form is always the same, and the
time is always valid.
An implementation is free to predefine other macros that use any of
the reserved names, such as names that contain two adjacent
underscores or a leading underscore followed by an uppercase letter.
For example, compilers often define macros to indicate the host or
target platforme.g., _ _linux_ _. Consult
your compiler''s documentation for details.
Examples
When
writing a container class template (see Chapter 10), it is important to detect when a template
parameter is an integral type. There are several ways to do this. One
way is to use type traits (Chapter 8). A template
declares a special tag for all integral types and a different tag for
all other types. The traits template is then specialized for the
integral types, which is repetitive, tedious, and error-prone. Using
a macro, however, reduces the opportunity for errors because the
macro body is written once. Example 11-1 shows how
the DECL_IS_INTEGER
macro specializes the
is_integer class template for each built-in
integral type.
Example 11-1. Defining type traits with a macro
// Type trait to test whether a type is an integer.
struct is_integer_tag {};
struct is_not_integer_tag {};
// The default is that a type is not an integral type.
template<typename T>
struct is_integer {
enum { value = 0 };
typedef is_not_integer_tag tag;
};
// Explicitly override the default for all integral types.
#define DECL_IS_INTEGER(T) template<> struct is_integer<T>
{ enum { value = 1 }; typedef is_integer_tag tag; }
DECL_IS_INTEGER(bool);
DECL_IS_INTEGER(char);
DECL_IS_INTEGER(signed char);
DECL_IS_INTEGER(unsigned char);
DECL_IS_INTEGER(int);
DECL_IS_INTEGER(unsigned int);
DECL_IS_INTEGER(short);
DECL_IS_INTEGER(unsigned short);
DECL_IS_INTEGER(long);
DECL_IS_INTEGER(unsigned long);
#undef DECL_IS_INTEGER
Example 11-2 shows another way that macros are used
when testing the string class. The
TEST macro calls a function and prints the result.
The TEST macro cannot be implemented as a function
because it uses the # operator.
Example 11-2. Testing functions
#include <iostream>
#include <string>
int main( )
{
using namespace std;
string s("hello, world");
#define TEST(func) cout << #func "=" << s.func << ''\n''
TEST(erase(9, 1));
TEST(erase(5));
TEST(find_first_not_of("aeiou"));
...
}
|
example that illustrates how macros are expanded. Try running the
example through your compiler to see if the results are correct.
(Other than whitespace, the results should be the same as what is
shown in the rest of this section.)
Example 11-3. Expanding macros
#define x x.y
#define STR(x) #x
#define XSTR(s) STR(s)
#define CONCAT(x, y) x ## y
#define PARENS(x) (x)
#define APPLY(x,y) x(y)
#define hello HI
x // x.y
CONCAT(ST, R)(hello) // "hello"
CONCAT(X,STR)(hello) // "HI"
CONCAT(S, TR)PARENS(hello) // STR(HI)
CONCAT(S, TR)(PARENS(hello)) // "PARENS(hello)"
APPLY(CONCAT(S, TR), hello) // "HI"
The first macro expansion shows how the macro name
x is not expanded in the replacement text. The
result is simply:
x.y
The second macro expansion shows how the CONCAT
macro forms a new token STR from its arguments.
After the CONCAT macro is evaluated, the text is
rescanned. The STR macro is then invoked with the
hello argument. Because the x
parameter is an operand of #, the argument is not
expanded. Instead, # is applied to
hello to produce the result:
"hello"
The third macro expansion is like the second, except it invokes
XSTR instead of STR. The
difference is that XSTR expands its argument,
s, because the replacement text,
STR(s), does not use the # or
## operators. Thus, XSTR(hello)
expands to STR(HI), which has the following
result:
"HI"
The fourth expansion also invokes CONCAT to
produce STR, but STR is not
followed by a left parenthesis, so it is not expanded as a macro.
Instead, it is followed by the PARENS macro. The
parameter of PARENS is not an operand of
# or ##, so it is expanded,
which means the argument hello expands to
HI, and the final result is:
STR(HI)
The fifth expansion is just like the second, but emphasizes how the
argument to STR is not expanded. The result is:
"PARENS(hello)"
The final macro expansion shows how to expand
hello as an argument to STR,
even when STR is the result of the
CONCAT macro. The parameters of
APPLY are expanded, resulting in the text
STR(HI), which expands to:
"HI"
See Also
#undef directive

