Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Обертка для призвольных данных.

41K
28 января 2010 года
gaga
44 / / 22.07.2009
Никто не знает способа красиво и эффективно сделать следующее: хочется, чтобы у любого типа данных появилось дополнительное поле (например, int State) и чтобы к нему было удобно обращаться? Т.е., допустим, есть структура
 
Код:
struct Foo{
 int a;
 double b;
};

и хочется приделать к ней дополнительное поле State - состояние данных, чтобы в идеале можно было обратиться как к родному полю Foo:
 
Код:
FooWrapped bar;
 Bar.State = bar.a = bar.b =  0;
41K
28 января 2010 года
gaga
44 / / 22.07.2009
Очевидное решение:
 
Код:
template<class T> class StateWrapper{
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;

Тут плохо то, что синтаксис в случае обращения по указателю довольно запутанный, плюс возникают проблемы накладных расходов при не очень умном компиляторе. Как сделать лучше я так и не придумал
12K
28 января 2010 года
Ghox
297 / / 26.07.2009
А что если наследование использовать?
Код:
template<typename T>
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> приведет к ошибке компиляции.
51K
28 января 2010 года
Indian
37 / / 23.12.2009
Код:
#include <iostream>
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.
41K
28 января 2010 года
gaga
44 / / 22.07.2009
Ghox, отличная идея! Жаль, что просто так не работает со встроенными типами. В принципе, решается созданием специализированных шаблонов для встроенных типов:
Код:
...
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, твой вариант плох тем, что все уже существующие типы придется переписывать, что не всегда возможно да и очень муторно.
3
28 января 2010 года
Green
4.8K / / 20.01.2000
Цитата: gaga

Здесь уже почти все хорошо, исключая накладные расходы на operator=. Не знаю, уберет ли компилятор создание временной переменной в return.
А еще плохо то, что придется для каждого встроенного типа определять свой шаблон. Может, можно как-нибудь для всех разом?)



Ну как-то так:

Код:
template<typename T, typename U=void>
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;
};
41K
29 января 2010 года
gaga
44 / / 22.07.2009
Green, отличное решение, спасибо. Я не знаком с boost и не буду его спользовать в текущем проекте, но твой пример выглядит весьма изящно. Обязательно запомню этот пример на будущее, а у себя, пожалуй, сделаю 2-3 специализированных шаблона для float, double, long и т.п.
3
29 января 2010 года
Green
4.8K / / 20.01.2000
Цитата: gaga
Green, отличное решение, спасибо. Я не знаком с boost и не буду его спользовать в текущем проекте, но твой пример выглядит весьма изящно. Обязательно запомню этот пример на будущее, а у себя, пожалуй, сделаю 2-3 специализированных шаблона для float, double, long и т.п.


Ну так не обязательно использовать буст (весь). Можно взять только эти шаблоны или же вообще написать свои аналоги, они несложные.

P.S. Кстати, в tr1 включили is_class. Забавно, что при этом не включили enable_if.

41K
29 января 2010 года
gaga
44 / / 22.07.2009
Green, ну да, можно, я, наверное, напишу свои, если возникнет необходимость.
Кстати, в любом случае надо еще написать операторы присваивания и преобразования даже для невстроенных типов, потому что иначе нельзя написать
 
Код:
StateWrapper<SomeType> a;
SomeType b = {3, 4};
a = b;
3
29 января 2010 года
Green
4.8K / / 20.01.2000
Цитата: gaga

Кстати, в любом случае надо еще написать операторы присваивания и преобразования даже для невстроенных типов, потому что иначе нельзя написать


Ну вообще... идея таких врапперов не очень хорошая.
Как я понял, ты хочешь, чтоб обернутый объект воспринимался остальным кодом, как объект который был обернут?
Тут могут начнутся проблемы, например, при использовании шаблонов, т.к. типы обернутого и оборачиваемого - это разные типы.

Я бы все же разделял интерфейсы обертки и оборачиваемого объекта.

41K
29 января 2010 года
gaga
44 / / 22.07.2009
Цитата: Green

Как я понял, ты хочешь, чтоб обернутый объект воспринимался остальным кодом, как объект который был обернут?
Тут могут начнутся проблемы, например, при использовании шаблонов, т.к. типы обернутого и оборачиваемого - это разные типы.



Ну да, ты правильно понял). Типы-то разные, но благодаря перегруженным операторам преобразования и присваивания выглядят точно как оборачиваемые. Т.е. можно написать как a=b, так и b=a, и передавать в один тип вместо другого.

Я хочу использовать это следующим образом: у меня есть парсер, который разбирает поток сообщений и кладет их по разным структурам. Сообщений много, порядка 50, структуры давно определены в соответствующем хедере. Вот я и хочу к каждой из них добавить поле State, которое автоматом меняется на STATE_NEW при получении сообщения. Вручную делать 50 оберток с полем State влом, вот я и решил так извратиться)

Что меня смущает, так это сможет ли компилятор(gcc3.3) без потерь встроить все это дело, чтобы избежать накладных расходов. Надо будет потом листинги ассемблерные глянуть.

5
30 января 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: gaga
Сообщений много, порядка 50, структуры давно определены в соответствующем хедере. Вот я и хочу к каждой из них добавить поле State, которое автоматом меняется на STATE_NEW при получении сообщения.

Наследование?

41K
30 января 2010 года
gaga
44 / / 22.07.2009
hardcase, ну так мы же на первой странице и сделали наследование, с шаблонами. В итоге ведь оно абсолютно ничем не отличается от обычного наследования, кроме того, что не надо вручную писать потомков для каждой из 50 структур, а они генерируются компиляторами при объявлении. Разве нет?
5
30 января 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: gaga
hardcase, ну так мы же на первой странице и сделали наследование, с шаблонами. В итоге ведь оно абсолютно ничем не отличается от обычного наследования, кроме того, что не надо вручную писать потомков для каждой из 50 структур, а они генерируются компиляторами при объявлении. Разве нет?

Отличается :) Вы пытаетесь убежать от проблемы вместо того чтобы решать ее. Сегодня вам потребовалось внедрить поле State, а завтра потребуется какой-нибудь метод добавить.
И, кстати, причем тут потомки - дописывать нужно предка, при том, это одноразовая операция, минут за 40 можно справиться, а при нормальной сноровке и редакторе с заменой по регуляркам можно вообще минут за 5.

41K
30 января 2010 года
gaga
44 / / 22.07.2009
Цитата: hardcase

И, кстати, причем тут потомки - дописывать нужно предка, при том, это одноразовая операция, минут за 40 можно справиться, а при нормальной сноровке и редакторе с заменой по регуляркам можно вообще минут за 5.


Ну, на мой взгляд, утверждение спорное. В предложенном решении есть свои плюсы: например, исходные типы остаются неизменными. Это значит, что можно будет использовать новые обернутые структуры одновременно со старыми и в разных сочетаниях. Причем, в данном конкретном случае, старые структуры можно будет использовать в программе на С. А необходимая функциональность может быть добавлена ведь и в шаблон.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог