ヘッダー専用ライブラリに静的データメンバーを持つ方法は?
-
13-12-2019 - |
質問
テンプレート化されていないライブラリクラスに静的メンバーを持つ最善の方法は何ですか、 クラスユーザーにメンバーを定義する負担をかけずに?
このクラスを提供したいとします。
class i_want_a_static_member
{
static expensive_resource static_resource_;
public:
void foo()
{
static_resource_.bar();
}
};
.
それからクラスのユーザーは静的メンバーをどこかに定義することを忘れてはいけません
(すでに答え 多くの
// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;
.
私は以下に答えを持っていますが、それはいくつかの欠点を持っています。もっと優雅な解決策がありますか?
解決
c ++ 17以上
非動的初期化のためのinline static
変数を使用:
struct Foo
{
inline static int I = 0;
};
.
と機能ローカル静的変数を使用する場合は、
struct Foo
{
static std::string& Bar()
{
static std::string S = compute();
return S;
}
};
.
c ++ 14以降
使用できるように、機能ローカル統計を使用します。
何らかの理由で静的 dataメンバーを本当に望む場合は、テンプレートトリックを使用できます。
template <typename T = void>
struct Foo
{
static int I = 0; // inline initialization only for simple types.
};
template <typename T>
int Foo<T>::I;
.
局所統計
動的初期化を必要とするリソースの場合、ローカル静的を使用するのが最善です。
ファイルスコープまたはクラススコープ統計が動的に初期化されている順序は未定義であり、一般に、初期化の一部として未初期化されていない静的を読み取ろうとすると、静的初期化順序Fiascoにつながります。局所静的は、最初の使用時に初期化された問題を解決します。
ローカル統計を使用するにはいくらかのわずかなオーバーヘッドがあります。 C ++ 11以降、初期化はスレッドセーフである必要があります。これは通常、任意のアクセスがアトミック読み取りと適切な予測ブランチによってゲートされていることを意味します。
他のヒント
私の解決策は、静的メンバーがテンプレートでは細かく機能し、このホルダーを基本クラスとして使用するため、テンプレートホルダークラスを使用することです。
template <typename T>
struct static_holder
{
static T static_resource_;
};
template <typename T>
T static_holder<T>::static_resource_;
.
ホルダークラスを使用する:
class expensive_resource { /*...*/ };
class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
void foo()
{
static_resource_.bar();
}
};
.
しかし、メンバーの名前がHolderクラスで指定されているので、複数の静的メンバーに同じホルダーを使用することはできません。
C ++ 17以降では、インライン変数を使用してこれを行うことができます。
static const inline float foo = 1.25f;
.