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

时间:2014-10-06 17:25:31

标签: c++ c++11 macros

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

我想在x.h中定义一个宏,如果存在SubClass的{​​{1}}(或X的任何其他后代),它将生成编译器错误不叫X。怎么做?

要求:

  • C ++ 11。
  • 如果需要,可能需要在INIT(SubClass)文件中调用它。
  • 可能要求subclass.cppSubClass中有完整的定义。
  • 我想支持的编译器至少是subclass.cppgcc
  • 除非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

1 个答案:

答案 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成员。因此,如果未定义此成员,则会出现错误。因此,您需要将宏放在类定义中。

与往常一样,如果用户真的想要,他们可以解决这个问题。例如,他们可以定义具有相同名称的另一个函数。最终,我认为你不能创建一个故意滥用证明的系统,但它应该可以解决诚实的错误。让我知道您对此解决方案的看法,也许我可以引入修改来解决它。