我想在类名列表上运行宏,以避免复制/粘贴错误和麻烦。
想象一下,作为一个简单的例子,我的SDK中的每个类都需要在使用之前调用静态分配方法。因此,每次添加新类时,我都必须在初始化时手动添加以下行:
MyNewClass::allocate();
我还需要为初始化和销毁做同样的事情。
所以,不是每次都手动执行此操作,我想知道是否有办法在某处编写所有类名的列表,然后定义一个宏来为列表中的每个类调用相应的方法。有些东西:
#define ALLOCATE( TheClass ) TheClass ## ::allocate();
但是我不想仅仅传递TheClass
作为参数,而是要传递我的类列表。所以致电:
ALLOCATE_ALL( ClassA, ClassB, ClassC )
它将扩展为:
ClassA::allocate();
ClassB::allocate();
ClassC::allocate();
最终,我希望能够定义一个类列表并让多个宏迭代它。有些东西:
ALLOCATE_ALL( MyClassList )
INIT_ALL( MyClassList )
DESTROY_ALL( MyClassList )
我已经看过可变参数宏但是,如果我理解了这个概念,你必须定义与最终参数数量一样多的宏;在我的情况下,这根本不可行。
这有可能吗?
感谢您提供任何帮助和/或反馈。
答案 0 :(得分:10)
如果您对拥有一个类列表感到满意,可以使用以下技巧:
#define MY_CLASSES X(ClassA) X(ClassB) X(ClassC)
然后你可以做类似的事情:
#define X(a) a::allocate();
MY_CLASSES
#undef X
要做其他事情,你可以这样做:
#define X(a) a::init();
MY_CLASSES
#undef X
答案 1 :(得分:2)
您可以使用可变参数函数模板:
#include <iostream>
// Thanks to Jarod42 for improving it !
template <class... TClasses>
void allocateAll() {
std::initializer_list<int>{(TClasses::allocate(), void(), 0)...};
}
struct C1 { static void allocate() { std::cout << "allocated C1\n"; } };
struct C2 { static void allocate() { std::cout << "allocated C2\n"; } };
struct C3 { static void allocate() { std::cout << "allocated C3\n"; } };
int main()
{
allocateAll<C1, C2, C3>();
return 0;
}
输出:
allocated C1
allocated C2
allocated C3
按照您传递类的顺序调用函数。
您还可以集中班级列表:
// Use a template instead of a function so you can typedef it
template <class... TClasses>
struct ClassesList {
static void allocateAll() {
std::initializer_list<int>{(TClasses::allocate(), void(), 0)...};
}
// Add any other utilities here
private:
ClassesList();
};
// Declare your list
using MyClassesList = ClassesList<C1, C2, C3>;
int main(int, char**) {
// Just as before
MyClassesList::allocateAll();
}
答案 2 :(得分:1)
#include <boost/preprocessor/seq/for_each.hpp>
#define MyClassList \
(ClassA) \
(ClassB) \
(ClassC)
#define ALLOCATE_ALL( R, DATA, ELEM ) \
ELEM :: allocate();
#define INIT_ALL( R, DATA, ELEM ) \
ELEM :: init();
//...
BOOST_PP_SEQ_FOR_EACH( ALLOCATE_ALL, _, MyClassList )
BOOST_PP_SEQ_FOR_EACH( INIT_ALL, _, MyClassList )
答案 3 :(得分:1)
要略微提高answer given by LindyLancer建议X-macros,您可以拥有单独的文件
// file my_classes.def
#ifndef MY_CLASS
#error MY_CLASS should be defined before including my_classes.def
MY_CLASS(ClassA)
MY_CLASS(ClassB)
/// etc...
#undef MY_CLASS
然后你会包含几个次,例如
#define MY_CLASS(Classname) class Classname;
#include "my_classes.def"
以后,在一些初始值设定项(或您的main
)
#define MY_CLASS(Classname) Classname::init();
#include "my_classes.def"
答案 4 :(得分:0)
您可以定义迭代的通用宏,但它的一次性定义很难看。这是因为每个参数都需要一个宏定义,最多可达编译器支持的最大嵌套级别数(我相信最小值至少为63,但GCC仅受可用内存的限制)。但由于它是通用的,你可能会发现它的其他用途。
对于最多5个,可能的实现是:
#define M_ITER(M, ...) \
M_ITER_(__VA_ARGS__, _5, _4, _3, _2, _1)(M, __VA_ARGS__)
#define M_ITER_(_1, _2, _3, _4, _5, X, ...) M_ITER ## X
#define M_ITER_1(M, X) M(X)
#define M_ITER_2(M, X, ...) M(X) M_ITER_1(M, __VA_ARGS__)
#define M_ITER_3(M, X, ...) M(X) M_ITER_2(M, __VA_ARGS__)
#define M_ITER_4(M, X, ...) M(X) M_ITER_3(M, __VA_ARGS__)
#define M_ITER_5(M, X, ...) M(X) M_ITER_4(M, __VA_ARGS__)
这基本上是BOOST_PP_SEQ_FOR_EACH
的实施方式。
然后,您可以将它用于您的目的:
#define ALLOCATE_ALL(...) M_ITER(ALLOCATE, __VA_ARGS__)
#define INIT_ALL(...) M_ITER(INIT, __VA_ARGS__)
#define DESTROY_ALL(...) M_ITER(DESTROY, __VA_ARGS__)
ALLOCATE_ALL(ClassA, ClassB, ClassC)
INIT_ALL(ClassA, ClassB, ClassC)
DESTROY_ALL(ClassA, ClassB, ClassC)