Обертка для призвольных данных.
int a;
double b;
};
и хочется приделать к ней дополнительное поле State - состояние данных, чтобы в идеале можно было обратиться как к родному полю Foo:
Bar.State = bar.a = bar.b = 0;
T Data;
int State;
};
StateWrapper<Foo> wrapped;
wrapped.Data.a = wrapped.Data.d = wrapped.State;
Тут плохо то, что приходится добавлять .Data при каждом обращении. Этого можно избежать перегрузкой оператора ->:
T* operator ->() { return &Data; } };
// Тогда можно написать
wrapped->a = wrapped->b = wrapped.State;
StateWrapper<Foo>* pWrapped = &wrapped;
(*pWrapped)->a = (*pWrapped)->b = pWrapped->State;
Тут плохо то, что синтаксис в случае обращения по указателю довольно запутанный, плюс возникают проблемы накладных расходов при не очень умном компиляторе. Как сделать лучше я так и не придумал
struct StateWrapper : public T
{
int State;
};
struct Foo
{
int a;
double b;
};
int main()
{
StateWrapper<Foo> FooWrapped;
FooWrapped.a = 1;
FooWrapped.b = 2;
FooWrapped.State = 3;
}
Update. Правда, для встроенных типов (int, float и т.д.) такое не получится - например, конструкция StateWrapper<int> приведет к ошибке компиляции.
using namespace std;
int main()
{
struct A{
int State;
};
struct B:A{
int x;
double y;
long z;
};
B C;
C.State=C.x=C.y=C.z=0;
return 0;
}
State существует, однако некоторые IDE его могут не увидеть.
Успешно компилируется на GCC 4.4.1.
template<> struct StateWrapper<double> {
int State;
double Val;
double& operator =(const double& newval) { Val = newval; return Val; }
operator double() { return Val; }
};
int main()
{
StateWrapper<double> DoubleWrapped;
DoubleWrapped = 3.4;
DoubleWrapped.State = 2;
double b = 1.2 + DoubleWrapped;
}
Здесь уже почти все хорошо, исключая накладные расходы на operator=. Не знаю, уберет ли компилятор создание временной переменной в return.
А еще плохо то, что придется для каждого встроенного типа определять свой шаблон. Может, можно как-нибудь для всех разом?)
Indian, твой вариант плох тем, что все уже существующие типы придется переписывать, что не всегда возможно да и очень муторно.
Здесь уже почти все хорошо, исключая накладные расходы на operator=. Не знаю, уберет ли компилятор создание временной переменной в return.
А еще плохо то, что придется для каждого встроенного типа определять свой шаблон. Может, можно как-нибудь для всех разом?)
Ну как-то так:
struct StateWrapper
{
int State;
double Val;
double& operator =(const T& newval) { Val = newval; return Val; }
operator const T&() const { return Val; }
};
template<typename T>
struct StateWrapper<T, typename boost::enable_if< boost::is_class<T> >::type> : T
{
int State;
};
Ну так не обязательно использовать буст (весь). Можно взять только эти шаблоны или же вообще написать свои аналоги, они несложные.
P.S. Кстати, в tr1 включили is_class. Забавно, что при этом не включили enable_if.
Кстати, в любом случае надо еще написать операторы присваивания и преобразования даже для невстроенных типов, потому что иначе нельзя написать
SomeType b = {3, 4};
a = b;
Кстати, в любом случае надо еще написать операторы присваивания и преобразования даже для невстроенных типов, потому что иначе нельзя написать
Ну вообще... идея таких врапперов не очень хорошая.
Как я понял, ты хочешь, чтоб обернутый объект воспринимался остальным кодом, как объект который был обернут?
Тут могут начнутся проблемы, например, при использовании шаблонов, т.к. типы обернутого и оборачиваемого - это разные типы.
Я бы все же разделял интерфейсы обертки и оборачиваемого объекта.
Как я понял, ты хочешь, чтоб обернутый объект воспринимался остальным кодом, как объект который был обернут?
Тут могут начнутся проблемы, например, при использовании шаблонов, т.к. типы обернутого и оборачиваемого - это разные типы.
Ну да, ты правильно понял). Типы-то разные, но благодаря перегруженным операторам преобразования и присваивания выглядят точно как оборачиваемые. Т.е. можно написать как a=b, так и b=a, и передавать в один тип вместо другого.
Я хочу использовать это следующим образом: у меня есть парсер, который разбирает поток сообщений и кладет их по разным структурам. Сообщений много, порядка 50, структуры давно определены в соответствующем хедере. Вот я и хочу к каждой из них добавить поле State, которое автоматом меняется на STATE_NEW при получении сообщения. Вручную делать 50 оберток с полем State влом, вот я и решил так извратиться)
Что меня смущает, так это сможет ли компилятор(gcc3.3) без потерь встроить все это дело, чтобы избежать накладных расходов. Надо будет потом листинги ассемблерные глянуть.
Наследование?
Отличается :) Вы пытаетесь убежать от проблемы вместо того чтобы решать ее. Сегодня вам потребовалось внедрить поле State, а завтра потребуется какой-нибудь метод добавить.
И, кстати, причем тут потомки - дописывать нужно предка, при том, это одноразовая операция, минут за 40 можно справиться, а при нормальной сноровке и редакторе с заменой по регуляркам можно вообще минут за 5.
И, кстати, причем тут потомки - дописывать нужно предка, при том, это одноразовая операция, минут за 40 можно справиться, а при нормальной сноровке и редакторе с заменой по регуляркам можно вообще минут за 5.
Ну, на мой взгляд, утверждение спорное. В предложенном решении есть свои плюсы: например, исходные типы остаются неизменными. Это значит, что можно будет использовать новые обернутые структуры одновременно со старыми и в разных сочетаниях. Причем, в данном конкретном случае, старые структуры можно будет использовать в программе на С. А необходимая функциональность может быть добавлена ведь и в шаблон.