我们使用 boost - 所以使用那个库应该没问题。
但是我从来没有设法创建一组模板来为您提供针对整个数据类型的正确专业化,而不是专门针对单个数据类型(我知道该怎么做)。
让我举个例子来尝试将其变为现实。我想要一组可以用作的类:
Initialized<T> t;
其中 T 可以是简单的基本类型、PODS 或数组。它不能是一个类,因为一个类应该有自己的构造函数,而覆盖它的原始内存是一个糟糕的主意。
初始化应该基本上是 memset(&t, 0, sizeof(t)); 在处理遗留结构时,它可以更轻松地确保运行时代码与调试代码没有区别。
在 SDT = 简单数据类型的地方初始化,应该简单地创建一个包装底层 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;
};
我专门为 T* 进行了初始化,以提供自然的指针行为。而且我有一个用于数组的 InitializedArray<>,它将元素类型和数组大小作为模板参数。但同样,我必须使用模板名称来区分——我对 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 采用'InitializedImpl '类型的右手操作数(或没有可接受的转换)
而如果我直接实例化正确的基类型(而不是派生类型):
int main()
{
InitializedImpl<int,false> i;
ASSERT(i == 0);
i = 9; // <- OK
}
现在我可以将 i 用作任何旧的 int。这就是我想要的!
如果我尝试对结构做同样的事情,就会出现完全相同的问题:
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 而不是继承我需要的东西,那么就不会有子类,也不会有传播问题。
想法?!...