Мета-программирование времени компиляции со строковыми литералами - PullRequest
0 голосов
/ 16 апреля 2010

Я пишу некоторый код, который действительно может быть использован для простого метапрограммирования во время компиляции. Обычно в качестве символов времени компиляции используются теги empty-struct. Мне нужно украсить теги некоторыми элементами конфигурации во время выполнения. статические переменные, кажется, единственный способ (для включения метапрограммирования), однако статические переменные требуют глобальных объявлений. В дополнение к этому пришло в голову это предложение Скотта Майерса (из третьего издания 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;
}

редактирование: Сделано в вики сообщества.

1 Ответ

1 голос
/ 16 апреля 2010

Я наконец понял, в чем проблема ... и ваше решение мало что решает, если оно есть.

Цель использования локальной статической переменной состоит в том, чтобы обеспечить инициализацию при первом использовании, таким образом будучи защищенным от «Порядка инициализации 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 для обнаружения того, что значение еще не было инициализировано, и отложить инициализацию значений, которые зависят от него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...