Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++11

Macro Magic

4.24/5 (6 votes)
5 Mar 2016CPOL 20.3K   127  
Everything you always wanted to know about Macros but were afraid to ask

Introduction

Think macros are simple, boring and of little use, huh?

Background

C++ templates are not a replacement to the C macros, but rather combined together creates a powerful instrument, which allow experienced programmers to implement interesting idioms like Execute Member Function If It Is Present.

Using the Code

So, what we can do with macros?

  1. Multi line

    C++
    // Literally equal to the #define MIN_(A, B) ((A) < (B) ? (A) : (B))
    #define MIN_(A, B) (\
                        (A) < (B) ? \
                        (A) : (B)\
                       )
  2. Variadic

    C++
    // Using PRINT_ERROR_("%s they be stealin my %s!", "oh noes", "bucket")
    //  will print "oh noes they be stealin my bucket" in to the standard error stream
    #define PRINT_ERROR_(...) fprintf(stderr, __VA_ARGS__)
  3. Concatenation

    As strings:

    C++
    #define HELLO_ "say hello to my little"
    #define SPACE_ " "
    #define WORLD_ "friend"
    
    // Will be ptr. to the compile-time constant C str. "say hello to my little friend"
    static auto const HELLO_WORLD_ = HELLO_""SPACE_""WORLD_;

    As tokens:

    C++
    #define NUMBER_FROM_DIGITS_(D1, D2, D3) D1 ## D2 ## D3
    
    static const auto MY_NUMBER_ = NUMBER_FROM_DIGITS_(1, 2, 3); // will be 123
  4. Stringification

    C++
    #define MAKE_STR_(STR1, STR2, STR3) #STR1""#STR2""#STR3
    
    // Will be ptr. to the compile-time constant C str. "paint_it_black"
    static auto const MY_STR_ = MAKE_STR_(paint, _it_, black);
  5. Call other

    C++
    #define M_S_(arg) #arg // stringify
    #define MAKE_STR__(arg) M_S_(arg)
    
    // Will be ptr. to the compile-time constant C str.
    // In MS VS 2013: "+2,147,483,647" (for 32 bit)
    // In modern GCC: "INT_MAX"
    static auto const MY_STR__ = MAKE_STR__(INT_MAX);
  6. Function-like AND recursion

    C++
    int f() throw() {return 1;}
    
    // Only expanded if appears with parentheses
    #define f() (f() + 1) // self-reference is NOT considered a macro call (passed unchanged)
    
    static const auto VAL_1_ = f(); // will be 2
    
    static auto const VAL_2_ = f; // will ptr. to the function
  7. One definition rule

    C++
    #define SUM(A, B) ((A) + (B))
    #define SUM(A, B) ((A) + (B)) // NO compile error here [the rule doesn't applied to macros]
    
    #define SUM(A, B) ((A)+(B)) // compile warning here (allowed redefinition)
    
    #define SUM(A, B) (  (A) + (B)   )
    #define SUM(A, B) ( (A   ) + 
    	(   B) ) // NO compile warning here (if spacers, their amount is ignored)
    #define SUM(A, B) ( (A   ) /*what if*/ + 
    	/*add some comments here*/ (   B) ) // NO redefinition here: comments count as spacers
  8. Redefinition "on the fly"

    C++
    #define SUM(A, B) ((A) + (B))
    
    // Will be 1 + 3 + 2 = 6
    static const auto VAL_ = SUM(1
    #undef SUM
    #define SUM + 3
    SUM, // new definition is used for argument pre-expansion
    2);  // original definition is used for argument replacement

Tests

Test code in the Ideone online compiler

C++
std::cout << MIN_(1 + 2, 3 + 4) << std::endl;                   // prints "3"
PRINT_ERROR_("%s they be stealin my %s!", "oh noes", "bucket"); // "oh noes they be stealin my bucket!"
std::cout << HELLO_WORLD_ << std::endl;                         // "say hello to my little friend"
std::cout << MY_NUMBER_ + 1 << std::endl;                       // prints 124
std::cout << MY_STR_ << std::endl;                              // prints "paint_it_black"
std::cout << MY_STR__ << std::endl;                             // prints "INT_MAX"
std::cout << VAL_1_ << std::endl;                               // prints "2"
std::cout << VAL_2_ + 10 << std::endl;                          // prints "1" (as a non-nil pointer)
std::cout << VAL_ << std::endl;                                 // prints "6"

Points of Interest

Warning! The result may vary due to the compiler used!

Know more magic? Share in the comments!

History

  • 5th March, 2016: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)