You can have static blocks in C++ as well – outside classes.
It turns out we can implement a Java-style static block, albeit outside of a class rather than inside it, i.e. at translation unit scope. The implementation is a bit ugly under the hood, but when used it’s quite elegant!
Downloadable version
There’s now a GitHub repo for the solution, containing a single header file: static_block.hpp
.
Usage
If you write:
static_block {
std::cout << "Hello static block world!\n";
}
this code will run before your main()
. And you can initialize static variables or do whatever else you like. So you can place such a block in your class’ .cpp
implementation file.
Notes:
- You must surround your static block code with curly braces.
- The relative order of execution of static code is not guaranteed in C++.
Implementation
The static block implementation involves a dummy variable initialized statically with a function. Your static block is actually the body of that function. To ensure we don’t collide with some other dummy variable (e.g. from another static block – or anywhere else), we need a bit of macro machinery.
#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__
#ifdef _MSC_VER
#define _UNUSED
#else
#define _UNUSED __attribute((unused))
#endif // _MSC_VER
and here is the macro work to put things together:
#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 _UNUSED = (function_name(), 0) ; \
static void function_name()
Notes:
- Some compilers do not support
__COUNTER__
– it’s not part of the C++ standard; in those cases the code above uses__LINE__
, which works too. GCC and Clang do support__COUNTER__
. - This is C++98; you don’t need any C++11/14/17 constructs. However, it’s not valid C, despite not using any classes or methods.
- The
__attribute ((unused))
might be dropped, or replaced with[[unused]]
if you have a C++11 compiler which doesn’t like the GCC-style unused extension. - This does not avert or help with the static initialization order fiasco, since while you know your static block will execute before
main()
, you are not guaranteed when exactly that happens relative to other static initializations.
Live Demo