Я наконец понял, в чем проблема ... и ваше решение мало что решает, если оно есть.
Цель использования локальной статической переменной состоит в том, чтобы обеспечить инициализацию при первом использовании, таким образом будучи защищенным от «Порядка инициализации Fiasco» (кстати, он не решает «Порядок уничтожения Fiasco»).
Но с вашим дизайном, если вы эффективно предотвращаете crash
, вы, тем не менее, не предотвращаете проблему использования переменной до ее использования.
ImportantObject<tbt> SinceSliceBread; // using an empty string
tbt::set_name("xyz");
Сравните со следующим использованием:
std::string& tbt::get_name() { static std::string MName = "xyz"; return MName; }
Здесь name
не только создается, но и инициализируется при первом использовании. Какой смысл использовать неинициализированное имя?
Ну, теперь, когда мы знаем, что ваше решение не работает, давайте немного подумаем. На самом деле мы хотели бы автоматизировать это:
struct tag
{
static const std::string& get_name();
static const std::string& get_fs_location();
};
(возможно с некоторыми аксессорами для их изменения)
Моим первым (и простым) решением было бы использование макроса (но не типа):
#define DEFINE_NEW_TAG(Tag_, Name_, FsLocation_) \
struct Tag_ \
{ \
static const std::string& get_name() { \
static const std::string name = #Name_; \
return name; \
} \
static const std::string& get_fs_location() { \
static const std::string fs_location = #FsLocation_; \
return fs_location; \
} \
};
Другим решением, в вашем случае, может быть использование boost::optional
для обнаружения того, что значение еще не было инициализировано, и отложить инициализацию значений, которые зависят от него.