简体   繁体   English

编译时元编程,带有字符串文字

[英]Compile time Meta-programming, with string literals

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. 绕开了斯科特·迈尔斯(Scott Myers)的建议(来自有效C ++的第三版),该建议涉及通过在函数中而不是类变量中声明静态变量的顺序来对静态变量的初始化进行排序。

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. 编辑:社区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"). 使用局部静态变量的目的是在首次使用时提供初始化,因此可以避免“ Initialization Order Fiasco”(顺便说一句,它不能解决“ Destruction Order Fiasco”)。

But with your design, if you effectively prevent the crash you do not however prevent the issue of using a variable before its value is used. 但是对于您的设计,如果您有效地防止crash ,则不会在使用变量的值之前避免使用变量的问题。

ImportantObject<tbt> SinceSliceBread; // using an empty string

tbt::set_name("xyz");

Compare with the following use: 与以下用途进行比较:

std::string& tbt::get_name() { static std::string MName = "xyz"; return MName; }

Here the name is not only created but also initialized on first use. 在这里,不仅创建name而且在首次使用时对其进行初始化 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: 实际上,我们想使它自动化:

struct tag
{
  static const std::string& get_name();
  static const std::string& get_fs_location();
};

(with possibly some accessors to modify them) (可能有一些访问者可以对其进行修改)

My first (and easy) solution would be to use a macro (bouh not typesafe): 我的第一个(也是简单的)解决方案是使用宏(不是类型安全的):

#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;                                     \
    }                                                         \
  };

The other solution, in your case, could be to use boost::optional to detect that the value has not been initialized yet, and postpone initialization of the values that depend on it. 在您的情况下,另一种解决方案是使用boost::optional来检测该值尚未初始化,然后推迟依赖该值的值的初始化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM