我有一个带有一些静态成员的类,并且我想运行一些代码来初始化它们(假设此代码无法转换成简单的表达式)。在Java中,我只会
class MyClass { static int myDatum; static { /* do some computation which sets myDatum */ } }
除非我弄错了,否则C ++不允许使用此类静态代码块,对吗?我应该怎么做呢?
我想要以下两个选项的解决方案:
对于第二种选择,我在想:
class StaticInitialized { static bool staticsInitialized = false; virtual void initializeStatics(); StaticInitialized() { if (!staticsInitialized) { initializeStatics(); staticsInitialized = true; } } }; class MyClass : private StaticInitialized { static int myDatum; void initializeStatics() { /* computation which sets myDatum */ } };
但这是不可能的,因为C ++(目前?)不允许初始化非常量静态成员。但是,至少这可以通过表达式将静态块的问题减少到静态初始化的问题…
事实证明,我们可以实现Java样式的静态块,尽管它是在类外部而不是在类内部,即在翻译单元范围内。内幕的实现有点丑陋,但是使用起来非常优雅!
该解决方案现在有一个GitHub存储库,其中包含一个头文件:static_block.hpp。
static_block.hpp
如果您写:
static_block { std::cout << "Hello static block world!\n"; }
此代码将在您的之前运行main()。您可以初始化静态变量,也可以执行其他任何操作。因此,您可以在类的.cpp实现文件中放置这样的块。
main()
.cpp
笔记:
静态块实现涉及使用函数静态初始化的虚拟变量。您的静态块实际上是该函数的主体。为了确保我们不会与其他虚拟变量发生冲突(例如,来自另一个静态块或其他任何地方),我们需要一些宏机制。
#define CONCATENATE(s1, s2) s1##s2 #define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2) #ifdef __COUNTER__ #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__) #else #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__) #endif // __COUNTER__
这是将内容组合在一起的宏工作:
#define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_)) #define STATIC_BLOCK_IMPL1(prefix) \ STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var)) #define STATIC_BLOCK_IMPL2(function_name,var_name) \ static void function_name(); \ static int var_name __attribute((unused)) = (function_name(), 0) ; \ static void function_name()
__COUNTER__
__LINE__
__attribute ((unused))
[[unused]]
Live Demo