1

単純なコンパイル時のメタプログラミングで実際に実行できるコードを書いています。コンパイル時のシンボルとして空の構造体タグを使用するのが一般的な方法です。いくつかの実行時構成要素でタグを装飾する必要があります。静的変数は(メタプログラミングを有効にするための)唯一の方法のようですが、静的変数にはグローバル宣言が必要です。このScottMyersの提案(Effective C ++の第3版から)を回避するために、静的変数をクラス変数としてではなく関数内で宣言することによって静的変数の初期化を順序付けることについて頭に浮かびました。

そこで、次のコードを思いつきました。私の仮説は、実行時に文字列リテラルを使用できるコンパイル時のシンボルを作成できるようにするというものです。依存するテンプレートクラスを初期化する前にランタイムフィールドにデータを入力する限り、これが正しく機能することを願っています。。

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

編集: コミュニティウィキを作成しました。

4

1 に答える 1

1

私はついに問題が何であったかを理解しました...そしてあなたの解決策は、もしあれば、あまり解決しません。

ローカル静的変数を使用する目的は、最初の使用時に初期化を提供することです。これにより、「初期化順序フィアスコ」から安全になります(ちなみに、「破壊順序フィアスコ」は解決されません)。

しかし、設計では、効果的に防止する場合でも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. 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.

于 2010-04-16T11:51:20.663 に答える