65.9K
CodeProject 正在变化。 阅读更多。
Home

宏魔法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.24/5 (6投票s)

2016 年 3 月 5 日

CPOL
viewsIcon

20782

downloadIcon

152

你一直想知道关于宏的一切,但又害怕去问

引言

认为宏很简单、枯燥且用处不大,是吗?

背景

C++ 模板 并非 C 的替代品,而是两者结合起来才能创造出强大的工具,让经验丰富的程序员实现有趣的惯用语,例如 如果成员函数存在则执行它

Using the Code

那么,我们能用宏做什么?

  1. 多行

    // Literally equal to the #define MIN_(A, B) ((A) < (B) ? (A) : (B))
    #define MIN_(A, B) (\
                        (A) < (B) ? \
                        (A) : (B)\
                       )
  2. 可变参数

    // 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. 串联

    作为字符串

    #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_;

    作为标记

    #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. 字符串化

    #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. 调用其他宏

    #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. 函数式 AND 递归

    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. 唯一定义规则

    #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. “即时”重新定义

    #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

测试

在 Ideone 在线编译器中测试代码

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"

关注点

警告!结果可能因使用的编译器而异!

知道更多魔法吗?在评论中分享!

历史

  • 2016年3月5日:初始版本
© . All rights reserved.