我正在编写一些实际上可以通过一些简单的编译时元编程实现的代码。通常使用空结构标记作为编译时符号。我需要用一些运行时配置元素来装饰标签。静态变量似乎是唯一的方法(启用元编程),但是静态变量需要全局声明。绕开了斯科特·迈尔斯(Scott Myers)的建议(来自有效C++的第三版),该建议涉及通过在函数中而不是类变量中声明静态变量的顺序来对静态变量的初始化进行排序。
所以我想出了以下代码,我的假设是,它将使我拥有一个编译时符号,其中的字符串文字可在运行时使用。只要希望在初始化依赖模板类之前填充运行时字段,我就不会丢失任何希望的东西,并且它将正常运行。 。
#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;
}
编辑:
制作社区Wiki。
最佳答案
我终于明白了问题出在哪里……而您的解决方案并不能解决很多问题。
使用局部静态变量的目的是在首次使用时提供初始化,因此可以避免“Initialization Order Fiasco”(顺便说一句,它不能解决“Destruction Order 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
来检测该值尚未初始化,然后推迟依赖该值的值的初始化。关于c++ - 编译时元编程,带有字符串文字,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2652164/