0

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);
Ufx
  • 2,595
  • 12
  • 44
  • 83

1 Answers1

2

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!

rabensky
  • 2,864
  • 13
  • 18
  • Hmm... without the `##` the code compiles correctly for me. However, with the `##` the code doesn't compile even with `SERVER_RE_2`. Tried on `g++` and `clang++`. – rabensky May 31 '15 at 15:31
  • I use MSVC120. My errors for your code http://pastebin.com/5T6124Pu. (But it compiles if use RE_1 RE_2 RE_3 instead of RE) – Ufx May 31 '15 at 23:20
  • 1
    @Ufx It's a visual C++ bug! But there's a work around - see my new edit – rabensky Jun 01 '15 at 03:33
  • rabensky Thanks a lot! Now it's work. VS underlines by red line this macro but this is not a big problem. Does this code work on gcc and clang? – Ufx Jun 01 '15 at 04:02
  • 1
    @Ufx yes :) Just tested to make sure. – rabensky Jun 01 '15 at 07:34