C++宏在子类未使用另一个宏时失败
C++ macro to fail when a subclass hasn't used another macro
我有一个在x.h
中声明并在x.cpp
中定义的类X
,它必须在静态初始化阶段使用宏INIT(X)
运行一些代码(在集中位置注册一些类元数据)。X
的任何子类Y
(y.h
中的声明,包括x.h
,y.cpp
中的定义)也是如此——它必须在全局范围内运行INIT(Y)
。现在,如果每个子类都已初始化,我想创建一个静态检查。此外,我不知道我将链接多少X
子类。
我想在x.h
中定义一个宏,如果存在未调用INIT(SubClass)
的X
的SubClass
(或X
的任何其他后代),该宏将生成编译器错误。怎么做?
要求:
- C++11
- 如果需要,可以要求在
subclass.cpp
文件中调用它 - 可以要求CCD_ 18在CCD_
- 我想要支持的编译器至少是
gcc
和msvc
- 它不应该在导入
x.h
的someotherclass.cpp
中生成错误,除非它定义了X
的子类 - 错误可以是任何类型的编译器错误,不一定必须是
#error
,例如未定义的变量也可以 - 此宏的代码可能需要对
X
类进行额外的更改,但不需要对其任何子类进行更改 INIT
放在subclass.cpp
的任何位置都必须工作
如果我不需要修改X
的任何子类来将其声明和定义放在INIT
中,那么在X
的新基类中定义一个伪抽象方法就可以了。
下面是该设计的模板代码,其中INIT
仅用于计算链接的X
子类的数量+1。/*???*/
可以用任何东西代替,只要它有效。
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
:
#include <cstdio>
#include "x.h"
// no error, since no new X subclass is defined
int main() {
printf("%dn", someGlobalInt()); // should print "2"
return 0;
}
正如注释中提到的n.m.,您可以使用Curioly Recurring Template Pattern。你可以这样做,我认为这比摆弄这些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成员。因此,如果未定义此成员,则会出现错误。因此,您需要将宏放在类定义中。
和往常一样,如果用户真的想,他们可以绕过这一点。例如,它们可以定义另一个具有相同名称的函数。最终,我不认为你可以创建一个故意防止滥用的系统,但它应该针对诚实的错误。让我知道你对这个解决方案的看法,也许我可以引入修改来修复它。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 运行同一解决方案的另一个项目的项目
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- C++从另一个类访问公共静态向量的正确方法是什么
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 使用std::transform将一个范围的元素添加到另一个范围中
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 修改函数中的指针(将另一个指针作为参数传递)
- 为什么我不能将一个对象push_back到属于另一个类的对象向量中?
- C++试图读取一个文件并输出到另一个文本文件
- 两个线程一个使用流 Api,另一个线程创建文件失败并出现错误ERROR_SHARING_VIOLATION
- xcb_get_image_reply另一个工作区/桌面上的窗口失败
- C++:为什么这个字符串输入失败,而另一个没有
- 类模板中的 typedef 的 SFINAE 失败是指另一个类模板中的 typedef
- C++宏在子类未使用另一个宏时失败
- 为什么当在另一个文件中更改外部常量时,链接器不会失败
- c++从另一个对象赋值失败
- 为什么一个代码编译了,另一个却失败了