Мы используем boost - поэтому с этой библиотекой все будет в порядке.
Но мне никогда не удавалось создать набор шаблонов, которые дают вам правильную специализацию для целого класса типов данных, в отличие от специализации для одного типа данных (что я знаю, как это сделать) .
Позвольте мне привести пример, чтобы попытаться донести это до земли. Я хочу иметь набор классов, которые можно использовать как:
Initialized<T> t;
Где T - простой базовый тип, PODS или массив. Это не может быть класс, поскольку ожидается, что у класса будет собственный конструктор, и перезапись его необработанной памяти - ужасная идея.
Инициализированный должен в основном memset (& t, 0, sizeof (t)); Это облегчает гарантию того, что исполняемый код не отличается от кода отладки при работе с устаревшими структурами.
Инициализируется, когда SDT = простой тип данных, должен просто создать структуру, которая обертывает базовый SDT и использует компиляторы t () для генерации конструктора, определенного компилятором по умолчанию для этого типа (он также может составить memset, хотя кажется более элегантным просто привести к t ().
Вот удар, используя Initialized <> для POD и Initialized <> для SDT:
// 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; }
};
А для СДЦ:
// 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 <> для массивов, который принимает как тип элемента, так и размер массива в качестве аргументов шаблона. Но опять же, я должен использовать имя шаблона, чтобы различать - я не умею использовать MPL достаточно хорошо, чтобы предоставить единый шаблон, который приводит к правильной специализации во время компиляции из одного имени (Initialized <>, в идеале).
Хотелось бы также иметь возможность предоставить перегруженный Initialized , чтобы для нескалярных значений пользователь мог определить значение инициализации по умолчанию (или значение 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 '=': не найден оператор, который принимает правый операнд типа '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 ++ позволял мне наследовать от базовых типов, я мог бы просто использовать технику наследования, и все было бы хорошо.
Или, если бы у меня был какой-то способ сказать компилятору экстраполировать все методы от parent к child, чтобы все допустимое для parent было допустимым для child, я был бы в порядке.
Или если бы я мог использовать MPL или type-traits для typedef вместо того, чтобы наследовать то, что мне нужно, тогда не было бы дочернего класса и проблемы с распространением.
Идеи?! ...