I’m writing some code which could really do with some simple compile time metaprogramming. It is common practise to use empty-struct tags as compile time symbols. I need to decorate the tags with some run-time config elements. static variables seem the only way to go (to enable meta-programming), however static variables require global declarations. to side step this Scott Myers suggestion (from the third edition of Effective C++), about sequencing the initialization of static variables by declaring them inside a function instead of as class variables, came to mind.
So I came up with the following code, my hypothesis is that it will let me have a compile-time symbol with string literals use-able at runtime. I’m not missing anything I hope, and that this will work correctly, as long as I populate the runtime fields before I Initialize the depending templates classes ? .
#include <string>
template<class Instance>
class TheBestThing {
public:
static void set_name(const char * name_in) {
get_name() = std::string(name_in);
}
static void set_fs_location(const char * fs_location_in) {
get_fs_location() = std::string(fs_location_in);
}
static std::string & get_fs_location() {
static std::string fs_location;
return fs_location;
}
static std::string & get_name() {
static std::string name;
return name;
}
};
struct tag {};
typedef TheBestThing<tag> tbt;
int main()
{
tbt::set_name("xyz");
tbt::set_fs_location("/etc/lala");
ImportantObject<tbt> SinceSlicedBread;
}
edit:
Made community wiki.
I’ve finally understood what the problem was… and your solution does not solve much, if any.
The goal of using local static variable is to provide initialization on first use, thus being safe from the “Initialization Order Fiasco” (by the way, it does not solve the “Destruction Order Fiasco”).
But with your design, if you effectively prevent the
crashyou do not however prevent the issue of using a variable before its value is used.Compare with the following use:
Here the
nameis not only created but also initialized on first use. What’s the point of using a non initialized name ?Well, now that we know your solution does not work, let’s think a bit. In fact we would like to automate this:
(with possibly some accessors to modify them)
My first (and easy) solution would be to use a macro (bouh not typesafe):
The other solution, in your case, could be to use
boost::optionalto detect that the value has not been initialized yet, and postpone initialization of the values that depend on it.