Compile time Meta-programming, with string literals

爱⌒轻易说出口 提交于 2019-12-10 12:17:33

问题


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.


回答1:


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 crash you do not however prevent the issue of using a variable before its value is used.

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. 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.



来源:https://stackoverflow.com/questions/2652164/compile-time-meta-programming-with-string-literals

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!