__VA_ARGS__ 可变参数宏 和 C/C++结构体序列化、json转换、xml转换。

我好像记得大学的教材是这么说的,我们现在学C++了,以前C语言是这样子的,

#define pi 3.1415926

 现在学C++推荐这么用

const double pi = 3.1415926;

好吧,不带这么埋汰宏的,感觉宏是C语言的糟粕似的。宏的作用是强势替换展开,它是帮你写程序的,不是给你定义变量的。

众所周知,C/C++运行时无法知道变量名字。比如说这个结构体

struct tagTest
{
    int id;             //id号
    string name;        //姓名
    string sex;		//性别
}

如果要互转json,大概需要这么写

void tagTest::ToJson(json::Value &va)
{
    va["id"] = id;
    va["name"] = name.c_str();
    vc["sex"] = sex.c_str();
}

void tagTest::FromJson(json::Value &va)
{
    id = ...;
    name = ...;
    sex = ...;
}

如果你有100个结构体,就要写100个这样的fromto,还容易写错,程序员虽然一直孜孜不倦的坐在电脑旁码字,但是绝对不是勤劳的人。

要是能自动化就好了呀,下面就开始引入宏了。最终的效果,我们是要这样子的:

struct tagTest
{
    tagTest()
    {
        REG_MEMBERS(id,name,sex) //记录需要转换的成员。
    }
    int id;             //id号
    string name;        //姓名
    string sex;		//性别
}

REG_MEMEBERS这个宏的参数是不定长的,不要想着把这个不定长参数直接丢给va_start,va_args,va_end。va_args第2个参数就需要给出类型,可是现在谁也不知道类型啊。

看一下微软的文档,https://docs.microsoft.com/en-us/cpp/preprocessor/variadic-macros?view=msvc-160,气死人了,网上也是到处都这样的代码。C99定义的__VA_AGRS__,难道只是为了方便丢给printf处理吗?

REG_MEMBERS宏定义的格式: #define REG_MEMBERS(...)

第一个需要解决的问题,你到底有几个参数?

先给出这段代码,得出参数个数。

#define ARG_COUNTX(...)  A1X(__VA_ARGS__)
#define A3X(x) x
#define A1X(...) A3X(A4X(__VA_ARGS__, 3, 2, 1, 0))
#define A4X(_1_, _2_, _3_, count, ...) count

如果调用ARG_COUNTX(a,b,c),结果=3,也就是参数的数量。不太好理解吧,由于VC有些不是BUG的BUG,中间需要一些宏转换,gcc不需要这样转换,主要看这里

#define A4X(_1_, _2_, _3_, count, ...) count

第一步展开,A4X(a, b, c, 3, 2, 1, 0),第二步展开,a, b, c, 3, 2, 1, 0,看一下A4X的定义,3这个位置就是count,刚好返回了。

_1_, _2_, _3_ 这3个东西只是挤占参数位置的,没实际意义。

如果调用ARG_COUNTX(a,b),结果=2;

看一下展开,第一步展开,A4X(a, b, 3, 2, 1, 0),第二步展开,a, b, 3, 2, 1, 0。哈哈,2刚好又是count的位置,返回2了。

如果调用ARG_COUNTX(a,b,c,d),结果会等于d,因为d刚好在count这个位置上。

只支持3个,太少了。  下面这个支持4个了。 依此类推,可以很多个,100个是没问题。上限是多少,我也不知道,可能和编译器有关系。


#define A1X(...) A3X(A4X(__VA_ARGS__, 4, 3, 2, 1, 0))
#define A4X(_1_, _2_, _3_, _4_, count, ...) count

第二个需要解决的问题,都有哪些参数?

先理解一下这个

#define ARG_1(_1, ...) _1
#define ARG_2(_1, _2, ...) _2
#define ARG_3(_1, _2, _3, ...) _3

ARG_1(a,b,c) 返回a, ARG_2(a,b,c) 返回b,ARG_3(a,b,c) 返回c。

对于ARG_2的展开,_2刚好就是b,对不对?

对于ARG_3的展开,_3刚好就是c,对不对?

因为我们需要考虑100个参数的问题,所以有了下面这个代码,学名是:宏递归。

#define DoNames(x)	cout << TOSTRING(x) << endl; //把变量名打印出来

#define ARG_1(x, ...)	        DoNames(x)
#define ARG_2(x, ...)		ARG_1(x)	ARG_1(__VA_ARGS__)
#define ARG_3(x, ...)		ARG_1(x)	ARG_2(__VA_ARGS__)

#define REG_MEMBERS(...)        ARG_ ## ARG_COUNTX(__VA_ARGS__)(__VA_ARGS__)

这段代码无法运行的,简洁一点,容易理解。

ARG_COUNTX(a,b,c) 结果=3,

ARG_ ## ARG_COUNTX(__VA_ARGS__),结果就是ARG_3,其中##是宏里面的连接符号。

REG_MEMBERS(a,b,c)的效果实现:ARG_3(a,b,c)。

开始递归,

ARG_3(a, b, c)展开结果: ARG_1(a)    ARG_2(b, c)

ARG_2(b, c)展开结果: ARG_1(b)    ARG_1(c)

意思就是说,每次从__VA_ARGS__最左边挤出一个参数来,然后把剩下的参数传给下一级。

要扩充数量的话,就是按这样的格式继续增加了


#define ARG_4(x, ...)		ARG_1(x)	ARG_3(__VA_ARGS__)
#define ARG_5(x, ...)		ARG_1(x)	ARG_4(__VA_ARGS__)

天啊,我怎么这么啰嗦的。

上面这段代码是无法运行的,需要再转换,比如 ARG_ ## ARG_COUNTX(__VA_ARGS__) 它的##连接结果ARG_ARG_COUNTX(__VA_ARGS__) ,继续不下去的,现在给出正确的代码

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <typeinfo>  
#include <string>
#include "stdarg.h"
using namespace std;

#define ARG_COUNTX(...)  A1X(__VA_ARGS__)
#define A3X(x) x
#define A1X(...) A3X(A4X(__VA_ARGS__, 3, 2, 1, 0))
#define A4X(_1_, _2_, _3_, count, ...) count

#define PREPARE_MACRO(x)     x
#define CAT_(a, b) a ## b
#define CAT(a, b) CAT_(a, b)

#define TOSTRING(x)         #x //转为字符串返回

#define test_output(x)	{								\
	cout << "-----------------------------" << endl;	\
	cout << "变量名: " << TOSTRING(x) << endl;			\
	cout << "类型: " << typeid(x).name() << endl;		\
	cout << "内存地址: " << &x << endl;				\
}

#define DoNames(x)	        test_output(x)	

#define ARG_1(x, ...)	    DoNames(x)
#define ARG_2(x, ...)       ARG_1(x)	PREPARE_MACRO(ARG_1(__VA_ARGS__))
#define ARG_3(x, ...)	    ARG_1(x)	PREPARE_MACRO(ARG_2(__VA_ARGS__))

#define REG_MEMBERS(...)     \
	PREPARE_MACRO(CAT(ARG_, ARG_COUNTX(__VA_ARGS__))(__VA_ARGS__))


struct tagTest
{
	tagTest()
	{
		REG_MEMBERS(id,name,sex) //记录需要转换的成员。
	}
	int id;             //id号
	string name;        //姓名
	string sex;			//性别
};

int _tmain(int argc, _TCHAR* argv[])
{
	tagTest t;

	getchar();
	return 0;
}

运行结果

-----------------------------
变量名: id
类型: int
内存地址: 002CF748
-----------------------------
变量名: name
类型: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
内存地址: 002CF74C
-----------------------------
变量名: sex
类型: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
内存地址: 002CF76C

经过我啰嗦这么久,我们终于获得了3个有用的东西:变量名、数据类型,指针。 也就是“类型--名字--值”。

关键词:类型--名字--值。定义结构体时,加一段代码:REG_MEMBERS(id,name,sex) ,可以得到“类型--名字--值”列表。

看到这里大家应该就明白了,主要就是__VA_ARGS__获取参数个数和遍历,接着使用typeid()获取变量类型。其实可以利用宏的特性做多事情,比如反射啦,类工厂啦。都是需要宏配合。

让宏展开一万次吧,我只写一行。

如果还是不明白,那我们继续。。。。。

接下来有很多方法,比如说我喜欢给结构体提供一个基类。不管怎么做,原理上都是保存“类型--名字--值”三要素列表。

完整的结构体基类:CBaseStruct

//BaseStrut.h
#pragma once

#include <typeinfo>  
#include <string>
#include "stdarg.h"
#include <vector>
using namespace std;

#define STRUCTTYPE_int		1
#define STRUCTTYPE_stdstring	2
class CBaseStruct
{
public:
	struct __TagInfo 
	{
		unsigned char type_id;	//类型标注
		std::string type_name;	//类型名称
		void *var_address;	//变量指针
		std::string var_name;	//变量名
	};

	CBaseStruct()
	{
	}

	int __get_count()
	{
		return __vector.size();
	}

	__TagInfo &__get_member(int i)
	{	
		return __vector[i];
	}

	void FromJson()
	{
		int size = __vector.size();
		for (int i=0; i<size; i++)
		{
			__TagInfo &info = __vector[i];
			switch (info.type_id)
			{
			case STRUCTTYPE_int:
				break;
			case STRUCTTYPE_stdstring:
				break;
			}
		}
	}

	void ToJson()
	{
		int size = __vector.size();
		for (int i=0; i<size; i++)
		{
			__TagInfo &info = __vector[i];
			switch (info.type_id)
			{
			case STRUCTTYPE_int:
				cout << info.var_name << "	:	" << *(int *)info.var_address << endl;
				break;
			case STRUCTTYPE_stdstring:
				cout << info.var_name << "	:	" << *(std::string *)info.var_address << endl;
				break;
			}
		}
	}

	std::vector<__TagInfo> __vector;
};


#define REFLECT_Members(a) {\
	CBaseStruct::__TagInfo info;																			\
	info.type_name = typeid(a).name();																		\
	if(info.type_name == "int")										info.type_id = STRUCTTYPE_int;			\
	else if(info.type_name.find("string") != std::string::npos)		info.type_id = STRUCTTYPE_stdstring;	\
	info.var_address = &a;																					\
	info.var_name = #a;																						\
	__vector.push_back(info);																				\
}


//
#define ARG_COUNTX(...)  A1X(__VA_ARGS__)
#define A3X(x) x
#define A1X(...) A3X(A4X(__VA_ARGS__, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define A4X(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, _33_, _34_, _35_, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, count, ...) count

#define PREPARE_MACRO(x)     x
#define CAT_(a, b) a ## b
#define CAT(a, b) CAT_(a, b)

#define ARG_1(x, ...)		REFLECT_Members(x)
#define ARG_2(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_1(__VA_ARGS__))
#define ARG_3(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_2(__VA_ARGS__))
#define ARG_4(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_3(__VA_ARGS__))
#define ARG_5(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_4(__VA_ARGS__))
#define ARG_6(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_5(__VA_ARGS__))
#define ARG_7(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_6(__VA_ARGS__))
#define ARG_8(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_7(__VA_ARGS__))
#define ARG_9(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_8(__VA_ARGS__))
#define ARG_10(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_9(__VA_ARGS__))
#define ARG_11(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_10(__VA_ARGS__))
#define ARG_12(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_11(__VA_ARGS__))
#define ARG_13(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_12(__VA_ARGS__))
#define ARG_14(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_13(__VA_ARGS__))
#define ARG_15(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_14(__VA_ARGS__))
#define ARG_16(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_15(__VA_ARGS__))
#define ARG_17(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_16(__VA_ARGS__))
#define ARG_18(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_17(__VA_ARGS__))
#define ARG_19(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_18(__VA_ARGS__))
#define ARG_20(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_19(__VA_ARGS__))
#define ARG_21(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_20(__VA_ARGS__))
#define ARG_22(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_21(__VA_ARGS__))
#define ARG_23(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_22(__VA_ARGS__))
#define ARG_24(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_23(__VA_ARGS__))
#define ARG_25(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_24(__VA_ARGS__))
#define ARG_26(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_25(__VA_ARGS__))
#define ARG_27(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_26(__VA_ARGS__))
#define ARG_28(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_27(__VA_ARGS__))
#define ARG_29(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_28(__VA_ARGS__))
#define ARG_30(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_29(__VA_ARGS__))
#define ARG_31(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_30(__VA_ARGS__))
#define ARG_32(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_31(__VA_ARGS__))
#define ARG_33(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_32(__VA_ARGS__))
#define ARG_34(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_33(__VA_ARGS__))
#define ARG_35(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_34(__VA_ARGS__))
#define ARG_36(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_35(__VA_ARGS__))
#define ARG_37(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_36(__VA_ARGS__))
#define ARG_38(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_37(__VA_ARGS__))
#define ARG_39(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_38(__VA_ARGS__))
#define ARG_40(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_39(__VA_ARGS__))
#define ARG_41(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_40(__VA_ARGS__))
#define ARG_42(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_41(__VA_ARGS__))
#define ARG_43(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_42(__VA_ARGS__))
#define ARG_44(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_43(__VA_ARGS__))
#define ARG_45(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_44(__VA_ARGS__))
#define ARG_46(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_45(__VA_ARGS__))
#define ARG_47(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_46(__VA_ARGS__))
#define ARG_48(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_47(__VA_ARGS__))
#define ARG_49(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_48(__VA_ARGS__))
#define ARG_50(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_49(__VA_ARGS__))
#define ARG_51(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_50(__VA_ARGS__))
#define ARG_52(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_51(__VA_ARGS__))
#define ARG_53(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_52(__VA_ARGS__))
#define ARG_54(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_53(__VA_ARGS__))
#define ARG_55(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_54(__VA_ARGS__))
#define ARG_56(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_55(__VA_ARGS__))
#define ARG_57(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_56(__VA_ARGS__))
#define ARG_58(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_57(__VA_ARGS__))
#define ARG_59(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_58(__VA_ARGS__))
#define ARG_60(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_59(__VA_ARGS__))
#define ARG_61(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_60(__VA_ARGS__))
#define ARG_62(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_61(__VA_ARGS__))
#define ARG_63(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_62(__VA_ARGS__))
#define ARG_64(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_63(__VA_ARGS__))
#define ARG_65(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_64(__VA_ARGS__))
#define ARG_66(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_65(__VA_ARGS__))
#define ARG_67(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_66(__VA_ARGS__))
#define ARG_68(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_67(__VA_ARGS__))
#define ARG_69(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_68(__VA_ARGS__))
#define ARG_70(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_69(__VA_ARGS__))
#define ARG_71(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_70(__VA_ARGS__))
#define ARG_72(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_71(__VA_ARGS__))
#define ARG_73(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_72(__VA_ARGS__))
#define ARG_74(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_73(__VA_ARGS__))
#define ARG_75(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_74(__VA_ARGS__))
#define ARG_76(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_75(__VA_ARGS__))
#define ARG_77(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_76(__VA_ARGS__))
#define ARG_78(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_77(__VA_ARGS__))
#define ARG_79(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_78(__VA_ARGS__))
#define ARG_80(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_79(__VA_ARGS__))
#define ARG_81(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_80(__VA_ARGS__))
#define ARG_82(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_81(__VA_ARGS__))
#define ARG_83(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_82(__VA_ARGS__))
#define ARG_84(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_83(__VA_ARGS__))
#define ARG_85(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_84(__VA_ARGS__))
#define ARG_86(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_85(__VA_ARGS__))
#define ARG_87(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_86(__VA_ARGS__))
#define ARG_88(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_87(__VA_ARGS__))
#define ARG_89(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_88(__VA_ARGS__))
#define ARG_90(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_89(__VA_ARGS__))
#define ARG_91(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_90(__VA_ARGS__))
#define ARG_92(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_91(__VA_ARGS__))
#define ARG_93(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_92(__VA_ARGS__))
#define ARG_94(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_93(__VA_ARGS__))
#define ARG_95(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_94(__VA_ARGS__))
#define ARG_96(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_95(__VA_ARGS__))
#define ARG_97(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_96(__VA_ARGS__))
#define ARG_98(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_97(__VA_ARGS__))
#define ARG_99(x, ...)		ARG_1(x)	PREPARE_MACRO(ARG_98(__VA_ARGS__))


#define REG_MEMBERS(...)     \
	__vector.reserve(ARG_COUNTX(__VA_ARGS__)); \
	PREPARE_MACRO(CAT(ARG_, ARG_COUNTX(__VA_ARGS__))(__VA_ARGS__))

调用部份,main.cpp

#include "stdafx.h"
#include <stdio.h>
#include <iostream>

#include "BaseStruct.h"

struct tagTest : public CBaseStruct
{
	tagTest()
	{
		REG_MEMBERS(id,name,sex); //记录需要转换的成员。
	}
	int id;             //id号
	string name;        //姓名
	string sex;			//性别
};

int _tmain(int argc, _TCHAR* argv[])
{
	tagTest t;
	t.id = 123456;
	t.name = "张三";
	t.sex = "男";

	t.ToJson();

	getchar();
	return 0;
}

运行结果

id	:	123456
name	:	张三
sex	:	男

你可以扩展支持的数据类型, 可以扩展新的接口,譬如:FromXml, ToXml, FromRecordSet, ToRecordSet。

另一个常用的方法,不使用基类。 把vector直接展开到结构体中。类似于

struct tagTest : public CBaseStruct
{
        int id;             //id号
	string name;        //姓名
	string sex;	    //性别

        REG_MEMBERS(id,name,sex); //记录需要转换的成员。
};

好处也是很明显的,相关的语法提示可能没了。

 

本文为博主原创,转载请注明原作者与出处。

(完)

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用:建议使用__VA_ARGS__时与##配合使用;##__VA_ARGS__在设置log输出的定义时比较常见。 引用:程序开发或者看工程代码时可能在定义中有涉及到#、##、__VA_ARGS__和##__VA_ARGS__的使用,简单介绍下使用方法。#操作符是将其后面紧跟的符号变为字符串的形式。 #__VA_ARGS__是C语言定义中的一个特殊标识符,表示可变参数列表。它可以用来在定义中传递不定数量的参数。当我们在定义中使用#__VA_ARGS__时,它会被替换为传递给的所有参数,以逗号分隔的形式。这样,我们可以在定义中使用这些参数,类似于函数的参数。 而##__VA_ARGS__是在定义中使用可变参数列表时常见的形式。它的作用是在定义中使用可变参数列表时,可以将参数列表前的逗号省略掉。这样可以避免在定义中使用可变参数列表时出现额外的逗号。 所以,#__VA_ARGS__和##__VA_ARGS__都是在定义中使用可变参数列表时的常见用法,可以实现灵活的定义,提高代码的可读性和可维护性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [# ## __VA_ARGS__ ##__VA_ARGS__的使用说明](https://blog.csdn.net/hanxv_1987/article/details/106555870)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值