C++ 可变宏展开

C++ 可变宏展开,c++,c,macros,variadic-macros,C++,C,Macros,Variadic Macros,我想知道有没有办法有选择地调用C变量宏 首先,让我展示一些我想要实现的代码: 没有什么把戏吗 编辑: 我写了更多关于我真正想要什么的细节 我从答案中找到了一些线索并编辑了我的代码 typedef unsigned short ListHeader; template<typename T> inline const size_t GetSize(const T& _obj) {return sizeof(T);} inline const size_t GetSize

我想知道有没有办法有选择地调用C变量宏

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

没有什么把戏吗


编辑:

我写了更多关于我真正想要什么的细节

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

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);
};
typedef无符号短列表头;
模板
内联常量size_t GetSize(常量t&_obj){return sizeof(t);}
inline const size_t GetSize(const std::string&_str){return sizeof(ListHeader)+_str.size()+1;}
内联常量大小(常量标准::向量和向量)
{
总尺寸=0;
对于(自动项目:_vec)
{
总计+=GetSize(项目);
}
返回sizeof(ListHeader)+总计;
}
模板
内联常量大小(常量标准::向量和向量)
{
总尺寸=0;
对于(自动项目:_vec)
{
总计+=GetSize(项目);
}
返回sizeof(ListHeader)+总计;
}
#定义变量IMPL(_1,_2,_3,_4,_5,_6,_7,_8,N,…)N
#定义虚拟现实(…)虚拟现实(uuu虚拟现实,8,7,6,5,4,3,2,1)
#定义VARARG_IMPL2(base,count,…)base###count(u VA_ARGS uu)
#定义VARARG_IMPL(base,count,…)VARARG_IMPL2(base,count,VA_ARGS)
#定义VARARG(base,…)VARARG_IMPL(base,VA_NARGS(uuu VA_ARGS_uuu),uuu VA_ARGS_uu)
#定义SerialSize(…)VARARG(SerialSize,\uuu VA\u ARGS\uuuu)
#定义SerialSize1(_1)\
const size_t size(){return GetSize(_1);}
#定义SerialSize2(_1,_2)\
const size_t size(){return GetSize(_1)+GetSize(_2);}
#定义SerialSize3(_1,_2,_3)\
const size_t size(){return GetSize(_1)+GetSize(_2)+GetSize(_3);}
#定义SerialSize4(_1,_2,_3,_4)//相同的实现,参数计数除外:1..4
#定义SerialSize5(_1,_2,_3,_4,_5)//1…5
#定义SerialSize6(_1,_2,_3,_4,_5,_6)//1…6
#定义SerialSize7(_1,_2,_3,_4,_5,_6,_7)//1…7
#定义SerialSize8(_1,_2,_3,_4,_5,_6,_7,_8)//1..8
//请不要关心我的归档类的详细实现。
//我想现在不重要了。。
班级档案
{
公众:
模板
存档和运算符,(T&_val)//变量宏的逗号运算符
{
如果(阅读)
读取(&_val);
其他的
写入(&_val);
归还*这个;
}
存档并输出();
存档&in();
私人:
模板
存档与读取(T&);
模板
存档与写入(T&);
};
类可序列化
{
公众:
可序列化(空){}
虚~Serializable(void){}
虚拟常量大小\u t size()=0;
虚拟空序列化(存档&)=0;
虚拟空反序列化(存档&)=0;
};
#定义序列化格式(…)\
SerialSize(_VA_ARGS)\
作废序列化(存档和ar)\
{\
ar.out(),###uu VA_uargs\
}\
无效反序列化(存档和ar)\
{\
ar.in(),##uuu VA_uargs\
}
//用法:
结构数据包\u请求登录
:可公开序列化
{
std::字符串名;
std::字符串密码;
串行格式(名称、密码);
};
它在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;
}
$gcc-std=c99-Wall-pedantic test.c
美元/年
1 2 3
$cat test.c
#包括
#定义foo(arg,…)arg,####VA_uargs__
int main()
{
printf(“%d%d%d\n”,foo(1,2,3));
返回0;
}

您不能将宏调用放在
活页夹的参数中,因为它直接使用
##
运算符

binder(_VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#define binder(count, ...) arg##count(__VA_ARGS__)
=> arg##_VA_NARGS(__VA_ARGS__)(__VA_ARGS__)
=> arg_VA_NARGS(__VA_ARGS__)(__VA_ARGS__)
要替换参数,请使用中间宏

#define binder_impl(count, ...) arg##count(__VA_ARGS__)
#define binder(...) binder_impl( __VA_ARGS__ )

我不知道你的最终目标是什么,但这个bug突然向我袭来。

最大的诀窍是理解
以及
如何扩展。下面是一个用于Linux系统调用的示例(args的数量-1,因为第一个arg指的是系统调用的数量…请注意,与大多数其他示例不同,它因此以0结尾)


现在我可以通过以下方式定义一个系统调用:
#define open(…)syscall(uu NR_open,u VA_ARGS_uu)
,当使用3个参数调用open时(用于u NR_open的5个参数间接来自#包括unistd.h),它将扩展到
syscall3(5,(long)a,(long)b,(long)c)

欢迎使用堆栈溢出。请尽快阅读这一页。似乎您想要编写
foo(a1,a2,…,aN)
,并且希望扩展调用一个宏,该宏的名称取决于参数的数量?您给出的示例并不引人注目,因为您似乎只需要逗号分隔的参数,
\uuva\uargs\uu
提供了这些参数。你能详细说明你真正想要的输出吗?您能为几个(两个,也许三个)示例调用显示您想要的输出吗?我不知道是否有帮助。可能吧。我的第一个想法来自那篇文章。谢谢。我敢肯定他在这方面做得对。在宏中需要额外级别的间接寻址,以便将参数计数扩展为一个数字。幸运的是,它被扩展为一个可以组合的简单预处理器令牌。
,#VA_uargs_uu
是非标准的,而且您似乎缺少t的实现
binder(_VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#define binder(count, ...) arg##count(__VA_ARGS__)
=> arg##_VA_NARGS(__VA_ARGS__)(__VA_ARGS__)
=> arg_VA_NARGS(__VA_ARGS__)(__VA_ARGS__)
#define binder_impl(count, ...) arg##count(__VA_ARGS__)
#define binder(...) binder_impl( __VA_ARGS__ )
#define MKFNS(fn,...) MKFN_N(fn,##__VA_ARGS__,9,8,7,6,5,4,3,2,1,0)(__VA_ARGS__)
#define MKFN_N(fn, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n, ...) fn##n

#define syscall(...) MKFNS(syscall,##__VA_ARGS__)
#define syscall1(n,a) _syscall1(n,(long)(a))
#define syscall2(n,a,b) _syscall2(n,(long)(a),(long)(b))
#define syscall3(n,a,b,c) _syscall3(n,(long)(a),(long)(b),(long)(c))
#define syscall4(n,a,b,c,d) _syscall4(n,(long)(a),(long)(b),(long)(c),(long)(d))
#define syscall5(n,a,b,c,d,e) _syscall5(n,(long)(a),(long)(b),(long)(c),(long)(d),(long)(e))