我正在编写一些代码,这些代码可以通过一些简单的编译时元编程实现。通常的做法是使用empty-struct标记作为编译时符号。我需要用一些运行时配置元素来装饰标签。静态变量似乎是唯一的方法(启用元编程),但静态变量需要全局声明。为了解决这个Scott Myers的建议(来自Effective 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;
}
修改 制作社区维基。
答案 0 :(得分:1)
我终于明白了问题是什么......如果有的话,你的解决方案解决不了多少。
使用本地静态变量的目的是在首次使用时提供初始化,因此可以安全地使用“初始化命令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
检测该值尚未初始化,并推迟依赖于它的值的初始化。