当子类没有使用另一个宏时 C++ 宏失败

标签 c++ c++11 macros

我有一个类 Xx.h 中声明并在 x.cpp 中定义,它必须运行一些代码(在中注册一些类元数据一个集中的地方)在静态初始化阶段使用宏 INIT(X)。对于任何子类 Y(在 y.h 中声明,包括 x.h,在 y.cpp 中定义)也是如此X - 它必须在全局范围内运行 INIT(Y)。现在我想创建一个静态检查是否每个子类都已初始化。此外,我不知道我将链接多少个 X 子类。

我想在 x.h 中定义一个宏,如果存在 X(或任何其他后代)的 SubClass,它将生成编译器错误尚未调用 INIT(SubClass)X)。怎么做?

要求:

  • C++11。
  • 如果需要可以要求在subclass.cpp文件中调用。
  • 可以要求SubClasssubclass.cpp中有完整的定义。
  • 我想支持的编译器至少是gccmsvc
  • 它不应在导入 x.hsomeotherclass.cpp 中生成错误,除非它定义了 X 的子类。
  • 错误可能是任何类型的编译器错误,不一定是#error,例如 undefined variable 也可以。
  • 此宏的代码可能需要在 X 类中进行额外更改,但不需要在其任何子类中更改。
  • INIT 放在 subclass.cpp 中的任何地方都必须在所有包含之后工作。

X 的新基类中定义一个虚拟抽象方法是可行的,前提是我不需要不修改任何 X 的子类将它的声明放在那里并在 INIT 中定义。

下面是该设计的模板代码,其中 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("%d\n", someGlobalInt()); // should print "2"
    return 0;
}

最佳答案

作为 n.m.评论中提到,您可以使用 Curiously Recurring Template Pattern。你可以做这样的事情,我认为这比乱用这些 lambda 更清楚:

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>是不同的类(class)。实际工作是在我们不断产生的新基类中完成的。现在,基类将始终尝试调用它的派生类的静态 reserved_init 成员。因此,如果未定义此成员,则会出现错误。因此,您需要将宏放在类定义中。

一如既往,如果用户真的想要,他们可以绕过这个问题。例如,他们可以定义另一个具有相同名称的函数。最后,我不认为你可以创建一个系统来防止故意滥用,但它应该可以防止无心之失。让我知道您对此解决方案的看法,也许我可以引入修改来修复它。

关于当子类没有使用另一个宏时 C++ 宏失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26221482/

相关文章:

c++ - 为什么 std::make_move_iterator 适用于 vector<string> 但不适用于 vector<int>

c++ - 'char (&) [13]' 是什么意思?

c++ - 函数式 C++11 奇怪的行为

c - 当 MACRO 不包含任何内存位置时,为什么 sizeof(MACRO) 给出 4 个字节的输出?

c++ - 查找 boost 多精度 uint512_t 的第一组指令 (ffs)

c++ - 我的 C++ 软件是太多 exe 的集合,我该如何管理它

c++ - xcode\377 倒置 '?'

C++ lambda 表达式无法编译

c - 用于简单链表追加的通用 C 宏

C 调试宏(具有不同的调试 "sources")