Search code examples
c++boost-preprocessor

Boost.Preprocessor index list with macro


I am trying to use Boost.Preprocessor to do some compile-time work. I want to index a table using values that are computed in other macros. When I try I get the following error: "concatenation with '(' in macro 'BOOST_PP_BOOL_I' does not create a valid token."

This is the simplest code that produces the issue.

#define MY_TABLE (0, (1, BOOST_PP_NIL))
#define MY_INDEX_FUNCTION(x) (x)
void func() {
    int y = BOOST_PP_LIST_AT(MY_TABLE, MY_INDEX_FUNCTION(0));
}

It is pretty easy to determine that removing the parens in MY_INDEX_FUNCTION resolves the issue in this case. My actual code uses a much more complex function to calculate the table index in a much larger table.

Is there something that I can do or change that would fix this such that the parens and more complex macros don't cause problems?


Solution

  • The second parameter of BOOST_PP_LIST_AT takes an index/integer. It works with tricky preprocessor hacks under the hood. The parameter(expanded) should be exactly an integer-literal, not an integer inside parenthesis. The MY_INDEX_FUNCTION should be changed, so that the parameter passed to the BOOST_PP_LIST_AT is literally an integer-literal:

    #define MY_INDEX_FUNCTION(x)  x
    

    The macro does not work with arithmetic expressions, this will not work:

    #define MY_INDEX_FUNCTION(x) (x+1)
    NOR
    #define MY_INDEX_FUNCTION(x)  x+1
    

    But you can do this with

    #define MY_INDEX_FUNCTION(x) MY_INDEX_FUNCTION_ ## x
    #define MY_INDEX_FUNCTION_0 1
    #define MY_INDEX_FUNCTION_1 2
    #define MY_INDEX_FUNCTION_2 3
    //...
    

    This macro definitions can be created by a (python-)script

    def my_index_function(x):
        # insert the behavior of the macro here
        return x+1
    
    MACRO_NAME = "MY_INDEX_FUNCTION"
    INDEX_MAX = 255
    
    for x in range(INDEX_MAX):
        print("#define %s_%i %i" % (
            MACRO_NAME,
            x,
            my_index_function(x),
        ))
    
    print("#define %s(x) %s_ ## x" % (
        MACRO_NAME,
        MACRO_NAME,
    ))