gpt4 book ai didi

c++ - 可变宏扩展

转载 作者:太空宇宙 更新时间:2023-11-04 02:53:10 25 4
gpt4 key购买 nike

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

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

#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 中测试过,但没有一个能按我的意愿编译。

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

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

有没有什么技巧?


编辑:

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

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

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 中不起作用。

VC11的输出是这样的:

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

我能做些什么来修复它?

最佳答案

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

首先,确定你不能用C++模板解决问题。

如果做不到这一点,它也需要代码生成:以某种符号对您的类进行规范并生成包含所有序列化内容的代码。

还有一件事。您正在非常努力地诱使宏生成包含多个项的总和:

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

但是你忽略了你可以有一个 N 元函数来做同样的事情:

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

现在,宏不必生成多个函数调用项,中间使用 + 运算符,而只需生成逗号分隔的参数列表!

您也将原始程序中的事情复杂化了。该程序中的 printf 可以简单地实现:

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

关于c++ - 可变宏扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20039565/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com