可变参数宏扩展 [英] Variadic macro expanding

查看:98
本文介绍了可变参数宏扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道有什么方法可以选择性地调用C VARIADIC MACRO.

I want to know that is there any way to call a C VARIADIC MACRO selectively.

首先,让我展示一些我想要实现的代码:

First, let me show some code I want to achieve:

#include <stdio.h>

#define _VA_NARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define _VA_NARGS(...) _VA_NARGS_IMPL(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1) 
#define binder(count, ...) arg##count(__VA_ARGS__)
#define foo(...) binder(_VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#define arg1(_1) _1
#define arg2(_1, _2) _1, _2
#define arg3(_1, _2, _3) _1, _2, _3

int main()
{
    printf("%d %d %d", foo(11,22,33));
    return 0;
}

我在VC11,GCC4.8和Clang 3.4中进行了测试,但是没有一个可以按照我的意愿进行编译.

I tested it in VC11, GCC4.8 and Clang 3.4 but none of them could compile it as I wanted.

是的,我想通过其参数计数来调用宏,但是宏会扩展为:

Yes, I want to call a macro by count of its arguments, but macros are expanded to:

foo(...)
binder(count, ...)
arg_VA_NAGS(...)

没有花招吗?

我更详细地写了我真正想要的东西.

I Wrote in more detail about what I really want.

我从答案中找到了一些线索,并编辑了我的代码.

I found some clue from answers and edited my code.

typedef unsigned short ListHeader;

template<typename T>
inline const size_t GetSize(const T& _obj) {return sizeof(T);}

inline const size_t GetSize(const std::string& _str) {return sizeof(ListHeader) + _str.size() + 1;}

inline const size_t GetSize(const std::vector<std::string>& _vec)
{
    size_t total = 0;

    for (auto item : _vec)
    {
        total += GetSize(item);
    }

    return sizeof(ListHeader) + total;
}

template<typename T>
inline const size_t GetSize(const std::vector<T>& _vec)
{
    size_t total = 0;

    for (auto item : _vec)
    {
        total += GetSize<decltype(item)>(item);
    }

    return sizeof(ListHeader) + total;
}

#define VA_NARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)


#define VARARG_IMPL2(base, count, ...) base##count(__VA_ARGS__)
#define VARARG_IMPL(base, count, ...) VARARG_IMPL2(base, count, __VA_ARGS__) 
#define VARARG(base, ...) VARARG_IMPL(base, VA_NARGS(__VA_ARGS__), __VA_ARGS__)



#define SerialSize(...) VARARG(SerialSize, __VA_ARGS__)



#define SerialSize1(_1) \
    const size_t size() {return GetSize(_1);}
#define SerialSize2(_1,_2) \
    const size_t size() {return GetSize(_1) + GetSize(_2);}
#define SerialSize3(_1,_2,_3) \
    const size_t size() {return GetSize(_1) + GetSize(_2) +  GetSize(_3);}
#define SerialSize4(_1,_2,_3,_4) // same implementation except count of arguments: 1..4
#define SerialSize5(_1,_2,_3,_4,_5) // 1...5
#define SerialSize6(_1,_2,_3,_4,_5,_6) //1...6
#define SerialSize7(_1,_2,_3,_4,_5,_6,_7) //1...7
#define SerialSize8(_1,_2,_3,_4,_5,_6,_7,_8) //1..8


// Please don't care about detailed implementation of my Archive class.
// It's not important now I guess..
class Archive
{
public:
    template<typename T>
    Archive& operator, (T& _val) //comma operator for Variadic macro
    {
        if (reading)
            read(&_val);
        else
            write(&_val);

        return *this;
    }

    Archive& out();
    Archive& in();

private:

    template<typename T>
    Archive& read(T&);
    template<typename T>
    Archive& write(T&);
};



class Serializable
{
public:
    Serializable(void) {}
    virtual ~Serializable(void) {}

    virtual const size_t size() = 0;
    virtual void serialize(Archive&) = 0;
    virtual void deserialize(Archive&) = 0;
};


#define SerialFormat(...) \
    SerialSize(__VA_ARGS__) \
    void serialize(Archive& ar)\
    {\
        ar.out() , ##__VA_ARGS__ ;\
    }\
    void deserialize(Archive& ar)\
    {\
        ar.in() , ##__VA_ARGS__ ;\
    }


//usage:
struct Packet_ReqeustLogin
    : public Serializable
{
    std::string name;
    std::string password;

    SerialFormat(name, password);
};

它已在Xcode5和VC11中进行了测试,但在VC11中不起作用.

It was tested in Xcode5 and VC11 but It doesn't work in VC11.

VC11的输出如下:

VC11's output is like this :

警告C4002:宏'SerialSize1'的实际参数过多

warning C4002: too many actual parameters for macro 'SerialSize1'

该如何解决?

推荐答案

C预处理程序不是您要执行的操作的正确工具(即使您克服了这个问题).

The C preprocessor is not the right tool for what you're trying to do (even if you surmount this problem).

首先,请确保您无法使用C ++模板解决问题.

Firstly, be sure that you can't solve the problem with C++ templates.

如果失败,它也需要生成代码:某些东西以某种符号形式指定了您的类,并生成了包含所有序列化内容的代码.

Failing that, it calls for a code generation too: something which takes a specification of your classes in some notation and generates the code with all the serialization stuff.

这是另一回事.您正在非常努力地诱使宏生成具有多个项的求和:

Here is another thing. You're trying very hard to coax macros into generating a summation with multiple terms:

GetSize(arg1) + GetSize(arg2) + ... + GetSize(argN)

但是您忽略了可以执行相同操作的N元函数:

but you're overlooking that you can have an N-ary function which does the same thing:

GetSizes(arg1, arg2, ... , argN);

现在,该宏不必使用介于两者之间的+运算符来生成多个函数调用项,而只需用逗号分隔的args列表即可!

now, the macro doesn't have to generate multiple function call terms with a + operator in between, but only the comma separated list of args!

您也使原始程序中的事情变得过于复杂.该程序中的printf可以简单地实现:

You over-complicated things in your original program also. The printf in that program can be achieved simply:

$ gcc -std=c99 -Wall -pedantic test.c
$ ./a.out
1 2 3
$ cat test.c
#include <stdio.h>

#define foo(arg, ...) arg, ##__VA_ARGS__

int main()
{
  printf("%d %d %d\n", foo(1, 2, 3));
  return 0;
}

这篇关于可变参数宏扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆