#define directive | Defines a macro |
#define identifier definition #define identifier( ) definition #define identifier( ) definition #define identifier(identifier-list) 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.
|
Wherever a macro name appears as a distinct token after its 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." char companyName[] = NAME;
During the macro expansion phase of 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 = z #define PRINT(a) (::std::cout << (a) << '\n')
To use a function-like macro, the macro name must be followed by a 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( ) { DECLARE(int, x, 42); PRINT((x = 10, x+2)); }
In the macro replacement text, each occurrence of a parameter name is replaced by the corresponding argument. For example, the macro expansion for the previous example results in the following:
int main( ) { int x = 42; (::std::cout << (x = 10, x + 2) << '\n'); }
You must be extra cautious when using a template instantiation as a 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( ) DECL(int, zero); // Expands to int zero = int( ) DECL(std::map<int,int>, m); // Error
When a macro is expanded, the macro arguments are expanded, and each 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.
The following macros are predefined. Do not undefine or redefine any of the predefined macros.
Has the value 199711L. Future versions of the C++ standard will use a larger value. Nonconforming compilers should use a different value.
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.
Expands to the name, as a string literal, of the source file being compiled.
Expands to the line number, as a decimal constant, of the source file being compiled.
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++.
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.
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.
// 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.
#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 11-3 is a contrived 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.)
#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"
#undef directive