Search code examples
c++c++11macrosvariadic-macros

Need to fix my Variadic Macros


I want to use variadic macros but I get errors

#define SERVER_RE_1(ServerFunction, Type1)                          \
    {                                                               \
        Type1 arg1;                                                 \
        getData(args, arg1);                                        \
        sv. ## ServerFunction ## (ssl, arg1);                       \
    }

#define SERVER_RE_2(ServerFunction, Type1, Type2)                   \
    {                                                               \
        Type1 arg1;                                                 \
        Type2 arg2;                                                 \
        getData(args, arg1, arg2);                                  \
        sv. ## ServerFunction ## (ssl, arg1, arg2);                 \
    }

#define SERVER_RE_3(ServerFunction, Type1, Type2, Type3)            \
    {                                                               \
        Type1 arg1;                                                 \
        Type2 arg2;                                                 \
        Type3 arg3;                                                 \
        getData(args, arg1, arg2, arg3);                            \
        sv. ## ServerFunction ## (ssl, arg1, arg2, arg3);           \
    }

#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define SERVER_RE(...) GET_MACRO(__VA_ARGS__, SERVER_RE_3, SERVER_RE_2, SERVER_RE_1)(__VA_ARGS__)

-

SERVER_RE(signIn, std::string, std::string);

error C2065: 'signIn' : undeclared identifier
error C2275: 'std::string' : illegal use of this type as an expression

-

But SERVER_RE_2 works good.

SERVER_RE2(signIn, std::string, std::string);

Solution

  • Remove the extra ##, as in replace the lines

        sv. ## ServerFunction ## (ssl, arg1, arg2, arg3);           \
    

    with

        sv. ServerFunction (ssl, arg1, arg2, arg3);           \
    

    EDIT

    Can you try to compile the following code?

    #include <string>
    #define SERVER_RE_1(ServerFunction, Type1)                          \
        {                                                               \
            Type1 arg1;                                                 \
            getData(args, arg1);                                        \
            sv. ServerFunction (ssl, arg1);                       \
        }
    
    #define SERVER_RE_2(ServerFunction, Type1, Type2)                   \
        {                                                               \
            Type1 arg1;                                                 \
            Type2 arg2;                                                 \
            getData(args, arg1, arg2);                                  \
            sv.ServerFunction(ssl, arg1, arg2);                 \
        }
    
    #define SERVER_RE_3(ServerFunction, Type1, Type2, Type3)            \
        {                                                               \
            Type1 arg1;                                                 \
            Type2 arg2;                                                 \
            Type3 arg3;                                                 \
            getData(args, arg1, arg2, arg3);                            \
            sv.ServerFunction(ssl, arg1, arg2, arg3);           \
        }
    
    #define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
    #define SERVER_RE(...) GET_MACRO(__VA_ARGS__, SERVER_RE_3, SERVER_RE_2, SERVER_RE_1)(__VA_ARGS__)
    
    struct C{
      template<class T1>
      void signIn(int,T1){}
      template<class T1, class T2>
      void signIn(int,T1,T2){}
      template<class T1, class T2,class T3>
      void signIn(int,T1,T2,T3){}
    };
    
    template<class T1>
    void getData(int,T1){}
    template<class T1, class T2>
    void getData(int,T1,T2){}
    template<class T1, class T2, class T3>
    void getData(int,T1,T2,T3){}
    
    int main(){
      C sv;
      int args=0,ssl=0;
      SERVER_RE(signIn, std::string);
      SERVER_RE(signIn, std::string, std::string);
      SERVER_RE(signIn, std::string, std::string, std::string);
    }
    

    This is the full code that compiles - as is - for me in both g++ and clang++, in both c++11 and c++98 modes

    Edit 2

    That first warning warning C4003 makes me think that there is a basic problem with variadic macros here.

    Indeed, booting my windows and playing around in visual studio, there is a bug in visual studio in variadic macro expantion.

    You can see it for yourself with the following code:

    #include <stdio.h>
    #define AAA(a,b) printf("%d %d\n",a,b)
    #define BBB(...) AAA(__VA_ARGS__)
    int main(){
      AAA(1,2); // works
      BBB(3,4); // warning + error
    }
    

    But worry not! You can fix it! Use my above code, but replace the line

    #define SERVER_RE(...) GET_MACRO(__VA_ARGS__, SERVER_RE_3, SERVER_RE_2, SERVER_RE_1)(__VA_ARGS__)
    

    with

    #define GET_MACRO_X(X) GET_MACRO X
    #define SERVER_RE(...) GET_MACRO_X((__VA_ARGS__, SERVER_RE_3, SERVER_RE_2, SERVER_RE_1))(__VA_ARGS__)
    

    and that compiles in visual studio! YAY!