Хм ... Заголовок немного глоток, но я действительно не уверен, какая часть этого вызывает проблемы, я пробежался по нему множество раз и не могу точно определить, почему ...
Идея состоит в том, чтобы один экземпляр Choice мог хранить любое значение любого из типов, переданных в его список шаблонов ... Это похоже на объединение, за исключением того, что он отслеживает типхранится и рассматривает значения каждого типа как отдельные, что позволяет обойти ограничения C ++ для конструкторов в членах объединения.
В некоторых случаях это работает, но, похоже, возникают некоторые проблемы скод очисткиЯ начал получать segfaults, как только начал использовать эту структуру с std :: basic_string или аналогичными типами, переданными в списке аргументов, но я не понимаю, почему это может вызвать проблемы.
Это вроде какЭксперимент для себя, но я не вижу никакой причины, почему это не должно работать (скомпилировано в режиме C ++ 0x в g ++):
// virtual methods should provide a way of "remembering"
// the type stored within the choice at any given time
struct ChoiceValue
{
virtual void del(void* value) = 0;
virtual bool is(int choice) = 0;
};
// Choices are initialized with an instance
// of this structure in their choice buffer
// which should handle the uninitialized case
struct DefaultChoiceValue : public IChoiceValue
{
virtual void del(void* value) {}
virtual bool is(int choice) { return false; }
};
// When a choice is actually initialized with a value
// an instance of this structure (with the appropriate value
// for T and TChoice) is created and stored in the choice
// buffer, allowing it to be cleaned up later (using del())
template<int TChoice, typename T>
struct ChoiceValue
{
virtual void del(void* value) { ((T*)value)->~T(); }
virtual bool is(int choice) { return choice == TChoice; }
};
template<typename ... TAll>
struct Choice
{
};
template<typename T1, typename ... TRest>
struct Choice<T1, TRest...>
{
// these two constants should compute the buffer size needed to store
// the largest possible value for the choice and the actual value
static const int CSize = sizeof(ChoiceValue<0, T1>) > Choice<TRest...>::CSize
? sizeof(ChoiceValue<0, T1>) : Choice<TRest...>::CSize;
static const int VSize = sizeof(T1) > Choice<TRest...>::VSize
? sizeof(T1) : Choice<TRest...>::VSize;
IChoiceValue* _choice;
char* _choiceBuffer;
char* _valueBuffer;
Choice()
{
_choiceBuffer = new char[CSize];
_valueBuffer = new char[VSize];
_choice = new (_choiceBuffer) DefaultChoiceValue();
}
~Choice()
{
_choice->del(_valueBuffer);
delete[] _choiceBuffer;
delete[] _valueBuffer;
}
template<int TChoice, typename T>
T& get()
{
if(_choice->is(TChoice))
return *(T*)_valueBuffer;
else
{
_choice->del(_valueBuffer);
new (_valueBuffer) T();
_choice = new (_choiceBuffer) ChoiceValue<TChoice, T>();
return *(T*)_valueBuffer;
}
}
};
template<typename T1>
struct Choice<T1>
{
// required for the base case of a template
// with one type argument
static const int CSize = sizeof(ChoiceValue<0, T1>) > sizeof(DefaultChoiceValue)
? sizeof(ChoiceValue<0, T1>) : sizeof(DefaultChoiceValue);
static const int VSize = sizeof(T1);
// I have an implementation here as well in my code
// but it is pretty much just a copy of the above code
// used in the multiple types case
};
Спасибо большое, если кто-нибудь сможет узнать, что я 'я делаю неправильно:)