クラスのユーザーがそれについて知ることなく、私のテンプレートクラスに静的メンバー変数を持つことは可能ですか?
-
28-10-2019 - |
質問
私はこの玩具コードのようなテンプレートのコンテナクラスを持っています:
template <class ItemType> class MyVector
{
public:
MyVector() : _numItems(0), _items(NULL) {/* empty */}
/** Returns a reference to the first item in our array,
* or a default-constructed item if the array is empty.
*/
const ItemType & GetFirstItemWithDefault() const
{
return (_numItems > 0) ? _items[0] : _defaultItem;
}
[other methods omitted because they aren't relevant]
private:
int _numItems; // how many valid items (_items) points to
ItemType * _items; // demand-allocated
const ItemType _defaultItem;
};
このクラスは使用するのに非常に便利です。任意のコードは#include "myvector.h"だけで、タイプmyvectorやmyvectorなどのオブジェクトの宣言を開始できます。
ただし、私が気にすることの1つは、_DefaultItemメンバー変数の存在です。これは、getFirstitemWithDefault()にコンテナが空のときに有効な参照を返す機能を与えるだけです。異議は、私がn myvectorオブジェクトを宣言する場合、それは_defaultitemのnコピーも同様にramに存在することを意味するということです。 MyVectorごとではなく、プロセス。
したがって、明らかな解決策は、_defaultItem staticを作成することです。しかし、コストが伴う場合:それを行うと、古いコードが「myvector.h」を#includeして行くことができなくなりました。 ..これで、ユーザーは、.cppファイルの1つでその静的変数のストレージを必ず宣言する必要があります。これは(a)尻の痛みであり、(b)コードのユーザーが認識しなければならないことを意味します。クラスの内部実装の詳細の。 _DefaultItemはプライベートメンバー変数であるため、クラスのユーザーは、それについて考える必要があるか、それが存在することを認識する必要さえありません。 (そして、2つの別々のコードが両方ともストレージを宣言した場合、それぞれが他方を知らないことが同じことをした場合はどうなりますか?
したがって、私の質問は、MyVectorのユーザーがそれについて知る必要がないように、この静的なメンバー変数にC ++に1つの一意のストレージ(インスタンス化されたタイプのMyVectorごと)を自動的に提供するように指示する方法はありますか? (いくつかの一般的なケースだけでなく、MyVector <...>のすべての可能なインスタンス化に対して自動である必要があることに注意してください)
解決
それがテンプレートの場合、コンパイラはあなたのために魔法を行います。静的メンバーをヘッダーに入れるだけで、コンパイラはそれが一度インスタンス化されていることを確認します。
template <class ItemType>
class MyVector
{
public:
//...
private:
static const ItemType _defaultItem;
};
template <class ItemType>
const ItemType MyVector<ItemType>::_defaultItem;
他のヒント
そのデフォルトのアイテムを関数にローカルに静的にしてみませんか?
const ItemType & GetFirstItemWithDefault() const
{
static const ItemType _default;
return (_numItems > 0) ? _items[0] : _default;
}
これは、他の関数のデフォルトのアイテムに対して再度チェックしたい場合に望むものではないかもしれませんが、そのためには、それを別の関数に配置することができます(それは静的自体かもしれません):
static const ItemType& GetDefault() const
{
static const ItemType _default;
return _default;
}
デフォルトのアイテムにアクセスする必要がある場合は、その関数を呼び出します。
そうは言っても、デフォルトのアイテムを持っているとは本当に良くないと思います。 std::vector
また、それを持っておらず、それを必要としません。ベクトルがあるかどうかを確認するようにユーザーに指示するだけです empty
そして、やられます。隠された統計の問題の1つは、あなたが知らないことです ItemType
. 。それは大量のリソースを食べるクラスである可能性があり、あなたはちょうどその別のインスタンスを作成しました!たぶんそのクラスのデザインを再考し、その後、 std::vector
. :)
したがって、明らかな解決策は、_defaultItem staticを作成することです。しかし、コストが伴う場合は、それを行うと、古いコードが「myarray.h」を#includeして行くことができなくなりました。 ..これで、ユーザーは、.cppファイルの1つでその静的変数のストレージを必ず宣言する必要があります。
いいえ. 。この恐怖は懸念されていません。の template
s宣言することができます static
同じファイルの変数。
template <class ItemType> class MyVector
{
const ItemType _defaultItem;
};
template <class ItemType>
const ItemType MyVector<ItemType>::_defaultItem; // ok (no multiple symbols)
また、これに注意してください static
メンバーはIFの場合にのみインスタンス化されます GetFirstItemWithDefault()
呼ばれています。したがって、冗長な割り当てについても心配しないでください。
心配する唯一のことはそうです デフォルトのコンストラクターを提供します すべてに ItemType
として static
オブジェクトは、デフォルトのコンストラクターに一般的に依存します(すでに気にかけている必要があります)。それでおしまい。