我在X
中声明了一个类x.h
,并在x.cpp
中定义了必须在静态初始化阶段使用宏运行一些代码(在集中位置注册一些类元数据) INIT(X)
。同样适用于Y
中的任何子类y.h
(x.h
中的声明,包括y.cpp
,X
中的定义) - 它必须运行INIT(Y)
在全球范围内。现在我想创建一个静态检查,如果每个子类都已初始化。此外,我不知道将链接多少个X
子类。
我想在x.h
中定义一个宏,如果存在SubClass
的{{1}}(或X
的任何其他后代),它将生成编译器错误不叫X
。怎么做?
要求:
INIT(SubClass)
文件中调用它。subclass.cpp
在SubClass
中有完整的定义。subclass.cpp
和gcc
。msvc
定义了someotherclass.cpp
的子类,否则它不会在导出x.h
的{{1}}中生成错误。X
,例如未定义的变量也没问题。#error
类中的其他更改,但不能在其任何子类中进行更改。X
在所有包含后INIT
放入任何地方时必须有效。在subclass.cpp
的新基类中定义一个虚拟抽象方法,只要我没有要求不修改X
的任何子类以将其声明放在那里并定义在X
。
以下是该设计的模板代码,其中INIT
仅用于计算链接的INIT
子类的数量+ 1. X
可以替换为任何内容,只要它有效
/*???*/
:
x.h
#include <functional>
int &someGlobalInt();
class XInit {
public:
XInit(std::function<void ()> init) {
init();
}
};
#define INIT(cls) static XInit X_INIT_ ## cls = XInit([](){ \
++someGlobalInt(); \
/*???*/ \
})
class X {
/*???*/
};
/*???*/
:
x.cpp
#include "x.h"
int &someGlobalInt() {
static int x = 0;
return x;
}
INIT(X); // error without it
:
y.h
#include "x.h"
class Y: public X {};
:
y.cpp
#include "y.h"
INIT(Y); // error without it
:
main.cpp
答案 0 :(得分:1)
早上好在评论中提到,您可以使用奇怪的重复模板模式。你可以做这样的事情,我认为这比弄乱这些lambdas更清楚:
XInit.h
template <class T>
class XInit {
private:
static bool initialized;
static std::once_flag flag;
static void base_init<T>(){ std::call_once(flag, T::reserved_init);}
...
}
XInit.cpp
template <class T>
XInit<T>::initialized = XInit<T>::base_init();
现在您可以将宏定义为:
#define INIT(cls) static void reserved_init() {++someGlobalInt();}
现在你继承:
class X : public XInit<X> ...
请注意,如果您需要层次结构,那很好,只需执行:
class Y: public X, public XInit<Y>
请注意,此处没有任何多重继承,因为XInit<X>
和XInit<Y>
是不同的类。实际工作是在我们不断产生的新基类中完成的。现在,基类将始终尝试调用它的派生类'static reserved_init成员。因此,如果未定义此成员,则会出现错误。因此,您需要将宏放在类定义中。
与往常一样,如果用户真的想要,他们可以解决这个问题。例如,他们可以定义具有相同名称的另一个函数。最终,我认为你不能创建一个故意滥用证明的系统,但它应该可以解决诚实的错误。让我知道您对此解决方案的看法,也许我可以引入修改来解决它。