ブーストを使用しているため、そのライブラリを使用しても問題ありません。
しかし、単一のデータ型に特化するのではなく、データ型のクラス全体に適切な特殊化を提供する一連のテンプレートを作成することに頭を悩ませたことはありません (方法は知っています)。
これを現実のものにするための例を挙げましょう。次のように使用できる一連のクラスが必要です。
Initialized<T> t;
ここで、T は単純な基本型、PODS、または配列のいずれかです。クラスには独自のコンストラクターが必要であり、生のメモリを上書きすることはひどい考えであるため、クラスにすることはできません。
基本的に初期化する必要があります memset(&t, 0, sizeof(t)); これにより、従来の構造体を扱うときにランタイム コードがデバッグ コードと変わらないことを確認しやすくなります。
Initialized where SDT = simple data type は、基になる SDT をラッパーし、コンパイラ t() を使用してその型のコンパイラ定義のデフォルト コンストラクタを生成する構造体を単純に作成する必要があります (より洗練されているように見えますが、memset にもなる可能性があります)。単純に t() になります。
POD の場合は Initialized<> を、SDT の場合は Initialized<> を使用して、次のように突き刺します。
// zeroed out PODS (not array)
// usage: Initialized<RECT> r;
template <typename T>
struct Initialized : public T
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
// publish our underlying data type
typedef T DataType;
// default (initialized) ctor
Initialized() { Reset(); }
// reset
void Reset() { Zero((T&)(*this)); }
// auto-conversion ctor
template <typename OtherType> Initialized(const OtherType & t) : T(t) { }
// auto-conversion assignment
template <typename OtherType> Initialized<DataType> & operator = (const OtherType & t) { *this = t; }
};
SDT の場合:
// Initialised for simple data types - results in compiler generated default ctor
template <typename T>
struct Initialised
{
// default valued construction
Initialised() : m_value() { }
// implicit valued construction (auto-conversion)
template <typename U> Initialised(const U & rhs) : m_value(rhs) { }
// assignment
template <typename U> T & operator = (const U & rhs) { if ((void*)&m_value != (void*)&rhs) m_value = rhs; return *this; }
// implicit conversion to the underlying type
operator T & () { return m_value; }
operator const T & () const { return m_value; }
// the data
T m_value;
};
自然なポインターの動作を提供するために、Initialized を T* に特化しました。そして、要素の型と配列サイズの両方をテンプレート引数として受け取る、配列用の InitializedArray<> があります。しかし、繰り返しになりますが、区別するためにテンプレート名を使用する必要があります.1つの名前(理想的にはInitialized<>)からすべてコンパイル時に正しい特殊化をもたらす単一のテンプレートを提供するのに十分なMPLを理解していません.
オーバーロードされた Initialized<typename T, T init_value> も提供できるようになりたいと思っています。これにより、非スカラー値の場合、ユーザーはデフォルトの初期化値 (または memset 値) を定義できます。
回答に少し手間がかかるかもしれない質問をして申し訳ありません。これは、私自身の MPL の読み取りでは克服できなかったハードルのようですが、おそらくあなたの助けがあれば、この機能を突き止めることができるかもしれません!
以下のベンおじさんの回答に基づいて、次のことを試しました。
// containment implementation
template <typename T, bool bIsInheritable = false>
struct InitializedImpl
{
// publish our underlying data type
typedef T DataType;
// auto-zero construction
InitializedImpl() : m_value() { }
// auto-conversion constructor
template <typename U> InitializedImpl(const U & rhs) : m_value(rhs) { }
// auto-conversion assignment
template <typename U> T & operator = (const U & rhs) { if ((void*)&m_value != (void*)&rhs) m_value = rhs; return *this; }
// implicit conversion to the underlying type
operator T & () { return m_value; }
operator const T & () const { return m_value; }
// the data
T m_value;
};
// inheritance implementation
template <typename T>
struct InitializedImpl<T,true> : public T
{
// publish our underlying data type
typedef T DataType;
// auto-zero ctor
InitializedImpl() : T() { }
// auto-conversion ctor
template <typename OtherType> InitializedImpl(const OtherType & t) : T(t) { }
// auto-conversion assignment
template <typename OtherType> InitializedImpl<DataType> & operator = (const OtherType & t) { *this = t; }
};
// attempt to use type-traits to select the correct implementation for T
template <typename T>
struct Initialized : public InitializedImpl<T, boost::is_class<T>::value>
{
// publish our underlying data type
typedef T DataType;
};
そして、いくつかの使用テストを試しました。
int main()
{
Initialized<int> i;
ASSERT(i == 0);
i = 9; // <- ERROR
}
これにより、エラーが発生します: *binary '=' : no operator found which takes a right-hand operand of type 'InitializedImpl ' (または受け入れ可能な変換がありません)
一方、(派生型ではなく) 正しい基本型を直接インスタンス化する場合:
int main()
{
InitializedImpl<int,false> i;
ASSERT(i == 0);
i = 9; // <- OK
}
これで、古い int として i を使用できます。これは私が欲しいものです!
構造体に対して同じことをしようとすると、まったく同じ問題が発生します。
int main()
{
Initialized<RECT> r;
ASSERT(r.left == 0); // <- it does let me access r's members correctly! :)
RECT r1;
r = r1; // <- ERROR
InitializedImpl<RECT,true> r2;
r2 = r1; // OK
}
ご覧のとおり、コンパイラに Initialized をプロモートして真の T のように動作させるように指示する何らかの方法が必要です。
C++ で基本型から継承できる場合は、継承手法を使用するだけで問題ありません。
または、コンパイラに親から子へのすべてのメソッドを外挿するように指示する方法があれば、親で有効なものはすべて子で有効になるため、問題ありません。
または、必要なものを継承する代わりに、MPL または type-traits を typedef に使用できれば、子クラスはなく、伝播の問題もありません。
アイデア?!...