3

static const std::stringパラメータ名として使用されるいくつかの場所で sを定義するかなり大きなプロジェクトがあります。それらのいくつかは、静的初期化中に連結する必要があります。

foo.h:

struct Foo {
  static const std::string ParamSuffix;
};

foo.cpp:

const std::string Foo::ParamSuffix = ".suffix";

bar.h:

struct Bar {
  static const std::string ParamPrefix;
};

バー.cpp:

const std::string Bar::ParamPrefix = "prefix";

baz.h:

struct Baz {
    static const std::string ParamName;
};

baz.cpp:

const std::string Baz::ParamName = Bar::ParamPrefix + Foo::ParamSuffix;

static constメンバーが初期化される順序が定義されていないため、問題は明らかに「静的初期化の大失敗」です。

私は通常の解決策が嫌いです。つまり、これらの変数をすべて関数に置き換えます。

  1. これらの変数はたくさんあります。つまり、コードの変更がたくさんあります。
  2. 連結には特別な関数が必要なため、コード ベースの一貫性が失われ、さらに見苦しくなります。

私は現在、C++ 11を使用できません。これにより、その機能で物事が簡単になりconstexprます(と思います)。

問題はstatic const std::string、 s (またはラッパー オブジェクトなど)を連結して別の s を初期化できるトリックはありますstatic const std::stringか?

4

3 に答える 3

3

質問は: static const std::strings (またはラッパーオブジェクトなど) を連結して別の static const std::string を初期化できるトリックはありますか?

嫌いなものを除いて、些細なことはありません。静的文字列の関数を作成します。

ただし、重要な代替手段があります (たとえば、ハードコーディングされたすべての文字列を文字列コンテナー/文字列マップに置き換え、アプリケーションの起動時にマップをロードします)。

ただし、静的関数を使用することをお勧めします(あなたが拒否したソリューション)。

于 2014-01-03T10:11:08.007 に答える
2

std::string constそれが何らかの形で特別だと思うのはなぜですか。(ヒント:そうではありません)C++ 11を使用できたとしても、s定数式constexprを作成できないため、役に立ちませんstd:string(実行可能な定数式ではないメモリを割り当てる必要がある場合があります)。constexpr変換するために使用される文字列のようなクラスを処理できますstd::stringが、これらを連結して new を生成できるかどうかはわかりませんconstexpr

おそらくできることは、連結の一部として使用する必要がある文字列を抽出し、それらの値をマクロとして提供することです。文字列リテラル (char const[N]適切な の型を持つN) は、単純に並べて配置するだけで連結できます。

// foo.h
#define FOO_PARAM_SUFFIX ".suffix"
struct Foo {
    static const std::string ParamSuffix;
};

// foo.cpp:
std::string const Foo::ParamSuffix(FOO_PARAM_SUFFIX);

// bar.h:
#define BAR_PARAM_SUFFIX "prefix"
struct Bar {
    static std::string const ParamPrefix;
};

// bar.cpp:
std::string const Bar::ParamPrefix(BAR_PARAM_SUFFIX);

// baz.h:
#include "foo.h"
#include "bar.h"
#define BAZ_PARAM_NAME BAR_PARAM_PREFIX FOO_PARAM_SUFFIX

struct Baz {
    static std::string const ParamName;
};

// baz.cpp:
#include "foo.h"
#include "bar.h"
std::string const Baz::ParamName(BAR_PARAM_PREFIX FOO_PARAM_SUFFIX);

他の場所では使用されていないと思いBAZ_PARAM_NAMEますが、その場合も定義する必要はありません。実行できることを示すためだけに定義されています。の初期化は、それが定義されBar::ParamNameていないことを前提としています。BAZ_PARAM_NAME

于 2014-01-03T09:38:14.583 に答える
2

テキストが別の変数に依存していない場合は、型を から 配列 ala に変更することを検討してください。const std::stringクライアントconst charの使用法を強制的に変更することはあまりないかもしれませんが、作成する必要がある (または意図せず作成される)const char param_prefix[] = "prefix";新しい一時的な s を隠す可能性があります。std::stringそれらが使用される時間。

const charシステムをチェックしてください。ただし、これらの変数を他の定数の構築に安全に使用できることはほぼ確実ですが、他の sへの必然的な依存関係についてstd::stringは不運です。std::stringstd::string

既存の値を can - be-とcan const- be-にのみ依存するものにほどくのが難しすぎる場合、または十分なケースをカバーできない場合は、すべての定数への大規模な変更を追求する価値があります。charstd::stringconstchar

ラッパーの魅力は、使用のタイプとセマンティクスを同じに保つことができることです。そのためには、ランタイムで初期化されたこれらすべての文字列を、初期化されたオブジェクトと待機中のオブジェクトという 2 つの中心的なリストを調整する独自の型に置き換える必要があります。オブザーバー パターンが適切です。または、たとえば、コールバックのリストを登録し、main()それらがすべて成功を示すまで呼び出しをループして初期化を完了することができます。オブジェクトの初期化の少なくとも一部が静的であることがわかっている場合、1 つのオブジェクトをテストできるようになります。別の初期化ステータス。これにより、コンストラクターに完了を登録させる必要がなくなります。

よりスマートなソース コード変更ツール (awk など) の助けを借りてそれが可能である場合は、関数によってクリーンに返されるように定数を単純に変更する方がよい場合があります。

于 2014-01-03T10:17:06.533 に答える