wye*_*r33 1 c++ c-preprocessor c++11 c++14
使用X宏时,处理额外尾随逗号的最佳方法是什么?具体来说,我在文件中有以下设置test01.cpp
struct Foo {
#define X(name,val) int name;
#include "test01.def"
#undef X
Foo() :
#define X(name,val) name(val),
#include "test01.def"
#undef X
{}
};
int main(){
Foo foo;
}
Run Code Online (Sandbox Code Playgroud)
在test01.def,我有
X(foo,1)
X(bar,23)
Run Code Online (Sandbox Code Playgroud)
由于错误,这不会编译
test01.cpp: In constructor 'Foo::Foo()':
test01.cpp:10:5: error: expected identifier before '{' token
{}
Run Code Online (Sandbox Code Playgroud)
基本上,在成员初始化列表中的最后一个元素之后有一个尾随逗号.现在,我们可以通过添加虚拟变量来解决这个问题:
struct Foo {
private:
void * end;
public:
#define X(name,val) int name;
#include "test01.def"
#undef X
Foo() :
#define X(name,val) name(val),
#include "test01.def"
#undef X
end(nullptr)
{}
};
int main(){
Foo foo;
}
Run Code Online (Sandbox Code Playgroud)
但是,这有点难看.因此,有没有更好的方法来处理成员初始化列表中的尾随逗号?
这是另一个仍然有点丑陋的选择:
struct Foo {
#define X(name,val) int name;
#include "test01.def"
#undef X
Foo() :
#define X(name,val) name(val),
#define XLAST(name,val) name(val)
#include "test01.def"
#undef XLAST
#undef X
{}
};
int main(){
Foo foo;
}
Run Code Online (Sandbox Code Playgroud)
随着
#ifndef XLAST
#define XLAST X
#define CLEANUP
#endif
X(foo,1)
XLAST(bar,23)
#ifdef CLEANUP
#undef XLAST
#undef CLEANUP
#endif
Run Code Online (Sandbox Code Playgroud)
基本上,我们定义宏XLAST来处理最后的逗号.如果我们使用XLAST,我们必须手动取消定义它X,但是我们在没有明确定义它的情况下自动执行此操作.
既然你已经标记了这个C++ 14,解决这个问题最简单的方法是使用大括号或相等的初始化程序小号,而不是mem-initializer秒.
struct Foo {
#define X(name,val) int name = val;
#include "test01.def"
#undef X
// Foo() {} // uncomment if you do not want Foo to be an aggregate
};
Run Code Online (Sandbox Code Playgroud)
如果您想坚持使用预处理器解决方案,可以使用Boost.Preprocessor来执行此操作.您需要更改数据成员定义的格式,以便形成序列.
#define FOO_MEMBERS ((int,i,10)) ((long,j,20))
Run Code Online (Sandbox Code Playgroud)
我添加了指定任意数据类型的功能.
首先让我们声明并初始化这些数据成员
struct Foo
{
#define OP(s, data, elem) BOOST_PP_TUPLE_ELEM(3, 0, elem) \
BOOST_PP_TUPLE_ELEM(3, 1, elem) = \
BOOST_PP_TUPLE_ELEM(3, 2, elem);
BOOST_PP_SEQ_FOR_EACH(OP, , FOO_MEMBERS)
// expands to
// int i = 10; long j = 20;
#undef OP
Foo() = default; // default constructor
};
Run Code Online (Sandbox Code Playgroud)
BOOST_PP_SEQ_FOR_EACH将扩展OP序列中每个元素的宏FOO_MEMBERS.
BOOST_PP_TUPLE_ELEM只需从其元组参数中提取单个元素.
接下来,让我们给出Foo一个构造函数,它接受与每个数据成员相对应的参数并初始化它.
#define OP(s, data, elem) (BOOST_PP_TUPLE_ELEM(3, 0, elem) BOOST_PP_TUPLE_ELEM(3, 1, elem))
Foo(
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(OP, , FOO_MEMBERS))
// expands to
// int i, long j
) :
#undef OP
#define OP(s, data, elem) (BOOST_PP_TUPLE_ELEM(3, 1, elem)(BOOST_PP_TUPLE_ELEM(3, 1, elem)))
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(OP, , FOO_MEMBERS))
// expands to
// i(i), j(j)
#undef OP
{}
Run Code Online (Sandbox Code Playgroud)
我们用来BOOST_PP_SEQ_ENUM从扩展的结果中生成一个逗号分隔的列表BOOST_PP_SEQ_FOR_EACH.