zoukankan      html  css  js  c++  java
  • Macro Recursive

    http://stackoverflow.com/questions/6707148/foreach-macro-on-macros-arguments/13459454#13459454

    recursive macros are possible in C using a fancy workaround. The end goal is to create a MAP macro which works like this:

    #define PRINT(a) printf(#a": %d", a)
    MAP(PRINT, a, b, c) /* Apply PRINT to a, b, and c */

    The Map Macro

    The goal is to create a macro which performs some operation each element of a list.
    Doing that requires recursion, though, which the C preprocessor doesn't allow.
    Fortunately, there is a workaround.

    Basic Recursion

    First, we need a technique for emitting something that looks like a macro call, but isn't yet:

    #define MAP_OUT

    Imagine we have the following macros:

    #define A(x) x B MAP_OUT (x)
    #define B(x) x A MAP_OUT (x)

    Evaluating the macro A (blah) produces the output text:

    blah B (blah) --> blah B (blah)

    The preprocessor doesn't see any recursion, since the B (blah) call is just plain text at this point,
    and 
    B isn't even the name of the current macro.
    Feeding this text back into the preprocessor expands the call, producing the output:
     

    blah blah A (blah) --> blah blah A (blah)

    Evaluating the output a third time expands the A (blah) macro, carrying the recursion full-circle.
    The recursion continues as long as the caller continues to feed the output text back into the preprocessor.

    To perform these repeated evaluations, the following EVAL macro passes its arguments down a tree of macro calls:

    #define EVAL0(...) __VA_ARGS__
    #define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__)))
    #define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__)))
    #define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__)))
    #define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__)))
    #define EVAL(...)  EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))

    Each level multiplies the effort of the level before, evaluating the input 365 times in total.
    In other words, calling 
    EVAL ( A (blah) ) would produce 365 copies of the word blah, followed by a final un-evaluated B (blah).
    This provides the basic framework for recursion, at least within a certain stack depth.

    End Detection

    The next challenge is to stop the recursion when it reaches the end of the list.

    The basic idea is to emit the following macro name instead of the normal recursive macro when the time comes to quit:

    #define MAP_END(...)

    Evaluating this macro does nothing, which ends the recursion.

    To actually select between the two macros, the following MAP_NEXT macro compares a single list item against the special end-of-list marker ().
    The macro returns MAP_END if the item matches, or the next parameter if the item is anything else:

    #define MAP_GET_END() 0, MAP_END
    #define MAP_NEXT0(item, next, ...) next MAP_OUT
    #define MAP_NEXT1(item, next) MAP_NEXT0 (item, next, 0)
    #define MAP_NEXT(item, next)  MAP_NEXT1 (MAP_GET_END item, next)

    This macro works by placing the item next to the MAP_GET_END macro. If doing that forms a macro call,
    everything moves over by a slot in the 
    MAP_NEXT0 parameter list, changing the output.
    The 
    MAP_OUT trick prevents the preprocessor from evaluating the final result.

    Putting it All Together

    With these pieces in place, it is now possible to implement useful versions of theA and B macros from the example above:

    #define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
    #define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)

    These macros apply the operation f to the current list item x.
    They then examine the next list item, peek, to see if they should continue or not.
    The final step is to tie everything together in a top-level MAP macro:

    #define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0 ) )

    This macro places a () marker on the end of the list, as well as an extra 0 for ANSI compliance
    (otherwise, the last iteration would have an illegal 0-length list).
    It then passes the whole thing through 
    EVAL and returns the result.

    Evaluation Depth

    Each level of the EVAL macro multiplies the effort of the previous level by 3, but also adds one evaluation of its own.
    Invoking the macro as a whole adds one more level, taking the total to:

    1 + (3 * (3 * (3 * (3 * (3 * (1) + 1) + 1) + 1) + 1) + 1) = 365

    Other interesting combinations include:

    calls/level levels  total depth
    2           3       16
    2           4       32
    2           5       64
    3           3       41
    3           4       122
    3           5       365
    4           3       86
    4           4       342
    4           5       1366
    5           2       32
    5           3       157
    5           4       782

    https://github.com/swansontec/map-macro

    https://raw.github.com/swansontec/map-macro/master/map.h

    /*
     * Copyright (C) 2012 William Swanson
     *
     * Permission is hereby granted, free of charge, to any person
     * obtaining a copy of this software and associated documentation
     * files (the "Software"), to deal in the Software without
     * restriction, including without limitation the rights to use, copy,
     * modify, merge, publish, distribute, sublicense, and/or sell copies
     * of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     *
     * Except as contained in this notice, the names of the authors or
     * their institutions shall not be used in advertising or otherwise to
     * promote the sale, use or other dealings in this Software without
     * prior written authorization from the authors.
     */
    
    #ifndef MAP_H_INCLUDED
    #define MAP_H_INCLUDED
    
    #define EVAL0(...) __VA_ARGS__
    #define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__)))
    #define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__)))
    #define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__)))
    #define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__)))
    #define EVAL(...)  EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))
    
    #define MAP_END(...)
    
    #define MAP_OUT
    #define MAP_GET_END() 0, MAP_END
    #define MAP_NEXT0(item, next, ...) next MAP_OUT
    #define MAP_NEXT1(item, next) MAP_NEXT0 (item, next, 0)
    #define MAP_NEXT(item, next)  MAP_NEXT1 (MAP_GET_END item, next)
    
    #define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
    #define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
    #define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
    
    #endif

  • 相关阅读:
    aliyun搭博客从零到一
    centos8飞行驾驶舱和docker安装
    squid的三种模式
    Linux和windos路由
    ca认证(https)
    shell脚本1
    heartbeat双主高可用
    Linux字符界面字符颜色显示
    不同尺寸的图片垂直水平居中的三种形式
    两栏三栏自适应布局
  • 原文地址:https://www.cnblogs.com/shangdawei/p/3100889.html
Copyright © 2011-2022 走看看