在使用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;
}
在test01.def
中,我有
X(foo,1)
X(bar,23)
由于错误,无法编译
test01.cpp: In constructor 'Foo::Foo()':
test01.cpp:10:5: error: expected identifier before '{' token
{}
基本上,在成员初始化器列表的最后一个元素后面有一个逗号,现在,我们可以通过添加一个伪变量来解决这个问题:
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;
}
然而,这有点难看。因此,有没有更好的方法来处理成员初始化器列表中的尾部逗号?
编辑1
这里还有一个选择,仍然有点丑陋:
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;
}
沿着
#ifndef XLAST
#define XLAST X
#define CLEANUP
#endif
X(foo,1)
XLAST(bar,23)
#ifdef CLEANUP
#undef XLAST
#undef CLEANUP
#endif
基本上,我们定义宏XLAST
来处理最后的逗号,如果我们使用XLAST
,我们必须像X
一样手动取消定义它,但是在我们没有明确定义它的情况下,我们会自动取消定义。
3条答案
按热度按时间vdzxcuhz1#
既然你已经标记了这个C++14,解决这个问题最简单的方法就是使用 brace-or-equal-initializers代替
mem-initializer
s。如果你想坚持使用预处理器解决方案,你可以使用Boost.Preprocessor来完成,你需要改变你的数据成员定义的格式,使它形成一个sequence。
我还添加了指定任意数据类型的功能。
首先,让我们声明并初始化这些数据成员
X1 E2 F1 X将为序列X1 M2 N1 X中的每个元素扩展宏X1 M1 N1 X。
BOOST_PP_TUPLE_ELEM
只是从它的 tuple 参数中提取单个元素。接下来,让我们为
Foo
提供一个构造函数,该构造函数接受与每个数据成员对应的参数并对其进行初始化。我们使用
BOOST_PP_SEQ_ENUM
从BOOST_PP_SEQ_FOR_EACH
的扩展结果中生成一个逗号分隔的列表。Live demo
fcwjkofz2#
如果你声明
end
为std::nullptr_t
类型,编译器很可能会优化并删除它,读者也很清楚其意图。或者,您可以声明
char end[0];
(这不会占用任何空间),但某些编译器可能会拒绝它。当然,作为Pratorian answered,您可以使用一些X-macro友好的构造来代替。
2izufjch3#
对于任何寻求不涉及BOOST_PP依赖的解决方案的人来说,一个基于预处理器的替代方案(对普通老C也很有用)是使用预处理器处理 * leading * 逗号,这比处理 * trailing * 逗号容易得多。
测试: