4

I hava a macro to call static function for each args.

For example:

#define FOO(X) X::do();
#define FOO_1(X,Y) X::do(); Y::do();

My question is that I need to use foo with variable number of arguments, is it possible to use __VA_ARGS__ ?

Like the line below:

#define FOO(...) __VA_ARGS__::do() ? 

Thanks

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
Kennir
  • 541
  • 1
  • 5
  • 12
  • 3
    In the future, if you could take just 5 seconds to look at the preview of your question, realize that the formatting is completely messed up, and then try to clean it up, that might make it a lot easier for people to answer. :) SO *does* feature code formatting capabilities. You just have to select the code, and press a button. – jalf May 04 '13 at 09:35
  • Use variadic templates instead... – Kerrek SB May 04 '13 at 09:40
  • Yeah,I used c++11 feature, in fact, I need a marco to define a function like this: #define FOO(X) \ static void fooFunction() { \ X::do(); \ } can I use variadic templates instead ? Thanks – Kennir May 04 '13 at 09:47
  • @Kennir: You can. See my answer – Andy Prowl May 04 '13 at 09:53

3 Answers3

5

Macro expansion does not work like argument pack expansion with variadic templates. What you have will expand to:

X,Y::do();

And not to

X::do(); Y::do();

As you hoped. But in C++11 you could use variadic templates. For instance, you could do what you want this way:

#include <iostream>

struct X { static void foo() { std::cout << "X::foo()" << std::endl; }; };
struct Y { static void foo() { std::cout << "Y::foo()" << std::endl; }; };
struct Z { static void foo() { std::cout << "Z::foo()" << std::endl; }; };

int main()
{
    do_foo<X, Y, Z>();
}

All you need is this (relatively simple) machinery:

namespace detail
{
    template<typename... Ts>
    struct do_foo;

    template<typename T, typename... Ts>
    struct do_foo<T, Ts...>
    {
        static void call()
        {
            T::foo();
            do_foo<Ts...>::call();
        }
    };

    template<typename T>
    struct do_foo<T>
    {
        static void call()
        {
            T::foo();
        }
    };
}

template<typename... Ts>
void do_foo()
{
    detail::do_foo<Ts...>::call();
}

Here is a live example.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • btw: why there need three functions with different template arguments? – Kennir May 04 '13 at 12:07
  • @Kennir: I'm not sure I understand your question. What arguments? – Andy Prowl May 04 '13 at 12:08
  • sorry for my poor english. template template template why there need 3 types of template? – Kennir May 04 '13 at 12:17
  • @Kennir: OK, so first of all those are not "arguments", but class templates. The first one is the *primary template*, while the next two are *specializations* of that primary template. You may want to read about template specialization a bit, or ask a further question on SO - the topic is too broad to be answered in a comment. – Andy Prowl May 04 '13 at 12:20
1

You cannot do this directly, __VA_ARGS__ is always treated as a single unit consisting of all the parameters separated by a comma. The preprocessor provides no built-in way to find the number of parameters, to separate them or to loop over them.

This answer to a similar question shows the basic solution using the preprocessor: Find out how many items there are in your argument list and pass it on to a macro that does take this exact amount of parameters.

I’d recommend not to do this but instead use Andy Prowls C++11 solution or even restructure your code so you don’t need this at all.

Community
  • 1
  • 1
Sven
  • 22,475
  • 4
  • 52
  • 71
1

Actually you can partially workaround this.
You can directly and freely extract every member of neither __VA_ARGS__ nor variadic templates of C++11. But you can have the very first element. For example let's say we have a macro named OUT(...) and we want to produce std::cout << A << B << C ... where A, B, C are the variadic arguments of macro. Try this:

#include <iostream>

#define SEPERATOR <<
#define GET_1_OF(element1, ...) element1
#define GET_2_OF(element1, ...) element1 SEPERATOR GET_1_OF(__VA_ARGS__) 
#define GET_3_OF(element1, ...) element1 SEPERATOR GET_2_OF(__VA_ARGS__) 
#define BAR(...) GET_3_OF(__VA_ARGS__)
int main()
{
    std::cout << BAR(1,2,3,4,5);
    return 0;
}

This is of course not the solution you are after. But you can augment the number of GET_N_OF to do what you want. Note that SEPERATOR is << so that we MACRO can write 1 << 2 << 3 and so on.
Now, we have a problem in this code. Please change BAR(1,2,3,4,5) with BAR(1) You will see that it is giving an error. This is because it was expecting 3 arguments, although it is not problem to have more arguments (because it is variadic) we are having extra SEPERATOR. So in order to solve this problem instead of using BAR(...) use GET_N_OF(...) (since you know the number of arguments):

#include <iostream>

#define SEPERATOR <<
#define GET_1_OF(element1, ...) element1
#define GET_2_OF(element1, ...) element1 SEPERATOR GET_1_OF(__VA_ARGS__) 
#define GET_3_OF(element1, ...) element1 SEPERATOR GET_2_OF(__VA_ARGS__) 
#define GET_4_OF(element1, ...) element1 SEPERATOR GET_3_OF(__VA_ARGS__) 
#define GET_5_OF(element1, ...) element1 SEPERATOR GET_4_OF(__VA_ARGS__) 

int main()
{
    std::cout << GET_5_OF(1,2,3,4,5);
    std::cout << GET_1_OF(1);
    return 0;
}

Please note that if you do not know what you are doing do not use MACROs at all! My response was just to share fun MACRO code that may be beneficial for you. I always discourage the usage of MACROs until they are remarkably necessary.