如何提取__VA_ARGS__?

时间:2013-05-04 09:33:10

标签: c++ templates c++11 macros

我有一个宏来为每个args调用静态函数。

例如:

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

我的问题是我需要使用带有可变数量参数的foo,是否可以使用__VA_ARGS__

如下面一行:

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

谢谢

3 个答案:

答案 0 :(得分:5)

宏扩展不像带有可变参数模板的参数包扩展那样有效。你所拥有的将扩展到:

X,Y::do();

而不是

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

如你所愿。但在C ++ 11中,您可以使用可变参数模板。例如,你可以通过这种方式做你想做的事:

#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>();
}

你需要的就是这个(相对简单的)机器:

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();
}

这是live example

答案 1 :(得分:1)

您无法直接执行此操作,__VA_ARGS__始终被视为由逗号分隔的所有参数组成的单个单元。预处理器没有提供内置的方法来查找参数的数量,分离它们或循环它们。

This answer一个类似的问题显示了使用预处理器的基本解决方案:找出参数列表中有多少项,并将其传递给一个确实需要这个参数的宏。

我建议不要这样做,而是使用Andy Prowls C++11 solution甚至重新构建代码,这样根本就不需要这样做。

答案 2 :(得分:1)

实际上你可以部分解决这个问题 您可以直接并自由地提取C ++ 11的__VA_ARGS__和可变参数模板的每个成员。但你可以拥有第一个元素。例如,假设我们有一个名为OUT(...)的宏,我们想生成std :: cout&lt;&lt; A&lt;&lt; B&lt;&lt; C ...其中A,B,C是宏的可变参数。试试这个:

#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;
}

这当然不是您所追求的解决方案。但是你可以增加GET_N_OF的数量来做你想要的。请注意SEPERATOR<<,以便我们MACRO可以写1 << 2 << 3等等。
现在,我们在此代码中遇到了问题。请使用BAR(1,2,3,4,5)更改BAR(1)您将看到它发出错误。这是因为它期待3个参数,虽然拥有更多参数(因为它是可变参数)并不是问题,但我们有额外的SEPERATOR。所以为了解决这个问题而不是使用BAR(...)使用GET_N_OF(...)(因为你知道参数的数量):

#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;
}

请注意如果您不知道自己在做什么,请不要使用MACRO!我的回答只是分享有趣的MACRO代码,这可能对您有益。我总是不鼓励使用MACRO,直到它们非常必要。