Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Метатип (не знаю как назвать))) 
V
    Опции темы
borisbn
Дата 11.9.2013, 14:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Здравствуйте. Имеется такой набор классов:
Код
struct Base {
    virtual int id() const = 0;
};

template< class T, int ID >
struct Snake : public Base {
    T head;
    T body;
    T tail;
    virtual int id() const { return ID; }
};

struct Data {};

typedef Snake< Data, 1 > Type_1;
typedef Snake< Data, 2 > Type_2;
typedef Snake< Data, 3 > Type_3;
typedef Snake< Data, 4 > Type_4;


А вот применение.
Код
template< class T >
void fillSnake( T * t, const Data & data ) {
    t->head = data;
    t->body = data;
    t->tail = data;
}

...

Data data;
Base * ptr = 0;
if ( condition ) {
    if ( sub_condition ) {
        Type_1 * t = new Type_1();
        fillSnake( t, data );
        ptr = t;
    }
    else {
        Type_2 * t = new Type_2();
        fillSnake( t, data );
        ptr = t;
    }
}
else {
    if ( sub_condition ) {
        Type_3 * t = new Type_3();
        fillSnake( t, data );
        ptr = t;
    }
    else {
        Type_4 * t = new Type_4();
        fillSnake( t, data );
        ptr = t;
    }
}


Мне этот код не нравится:
  • много копи-паста - легко ошибиться.
  • на самом деле в функции fillSnake делается гораздо больше, и, соответственно, ей нужно передавать кучу параметров, что тоже не украшает код


Вопрос: можно ли тут что-то придумать, чтобы код выглядел как-то так:
Код
MetaType type;
if ( condition ) {
    if ( sub_condition ) {
        type = Type_1;
    }
    else {
        type = Type_2;
    }
}
else {
    if ( sub_condition ) {
        type = Type_3;
    }
    else {
        type = Type_4;
    }
}
type * t = new type;
t->head = data;
t->body = data;
t->tail = data;
ptr = t;


Спасибо.

P.S. Какой-то сумбурный вопрос получился, но, я надеюсь, вы поняли, что я хотел  smile 


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
akizelokro
Дата 11.9.2013, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



так чтоли?

Код

enum AhhaTypes { Type_1 = 1, Type_2 =2, Type_3 = 3, Type_4 = 4 };

struct Base {
    virtual int id() const = 0;
};
template< class T, AhhaTypes ID >
struct Snake : public Base {
    T head;
    T body;
    T tail;
    virtual int id() const { return ID; }
}
;

Не знаю, до определения конкретных функций компилится.
А вот пойдёт ли дальше , непонятно


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
borisbn
Дата 11.9.2013, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(akizelokro @  11.9.2013,  17:55 Найти цитируемый пост)
так чтоли?

Нет. Мне не нравится код, который использует эти типы.
И потом... Type_1 - это Snake, а не enum


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
akizelokro
Дата 11.9.2013, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Цитата(borisbn @  11.9.2013,  18:05 Найти цитируемый пост)
Нет. Мне не нравится код, который использует эти типы.
И потом... Type_1 - это Snake, а не enum


Тогда ничем не могу помочь. Всякие извраты навроде

Код

typedef Snake< Data > Type_1;
typedef Snake< Data> Type_2;
typedef Snake< Data> Type_3;
typedef Snake< Data> Type_4;

или reinterpret<cast> вряд ли тебе интересны. Хотя, к первому изврату ещё можно приладить что-то типа
Код


template <T>
struct Snake : Base
{
   int ID_;
....
}

template <int ID>
class SnakeID
{
  Snake snake;
  SnakeID () { snake.ID_ = ID; };
}


где ID запихнуть как переменную в Snake и передавать указатель на неё в fillSnake, раз ты всё равно в ptr пишешь ссылку на базовый класс для Snake. Хотя, всё равно проблематично, int придётся явно указывать на момент компиляции. Хотя, вроде скоро должен подтянутьсяпарень, который даст ответ на вопрос.

кстати, интересно, "auto" будет работать на этом этапе?

Это сообщение отредактировал(а) akizelokro - 11.9.2013, 19:16


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
baldina
Дата 12.9.2013, 10:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



borisbn, т.к. требуемый тип известен только во время выполнения, имхо нужно двигаться в сторону фабричного метода (но тогда всплывут нелюбимые enum).

PM MAIL   Вверх
borisbn
Дата 12.9.2013, 10:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(baldina @  12.9.2013,  10:40 Найти цитируемый пост)
имхо нужно двигаться в сторону фабричного метода

Думал об этом, но воплотить в код так и не получилось. Поможете ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
baldina
Дата 12.9.2013, 14:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



можно начать с 
Код

enum EMetaType  { MType_1, MType_2, MType_3, MType_4 };
MetaType * createAs (EMetaType t);
...
EMetaType type;
if ( condition ) {
    if ( sub_condition ) {
        type = MType_1;
    }
    else {
        type = MType_2;
    }
}
else {
    if ( sub_condition ) {
        type = MType_3;
    }
    else {
        type = MType_4;
    }
}

MetaType * t = createAs (type);

где 
Код

MetaType * createAs (EMetaType t) {
  switch (t) {
    case MType_1: return new Type_1;
    ...
  }
}
или
Код

MetaType * create_Type_1 () {
  return new Type_1;
}

MetaType * create_Type_2 () {
  return new Type_2;
}
...
MetaType * createAs (EMetaType t) {
  typedef MetaType (*creator_t)();

  // псевдокод для краткости
  map<EMetaType, creator_t> creators = { {MType_1 => create_Type_1}, {MType_2 => create_Type_2}... };

  return creators[t] ();
}

и закончить кодированием condition и sub_condition битовой маской, которую использовать в качестве ключа для соответствующей функции создания объекта

Добавлено через 5 минут и 3 секунды
в последнем случае - никаких enum, получится что-то вроде

Код

int key_for_Type_1 = CONDITION1_BIT|CONDITION2_BIT...;
int key_for_Type_2 = CONDITION2_BIT|CONDITIONN_BIT...;
...
creators[key_for_Type_1]  = create_Type_1;
creators[key_for_Type_2]  = create_Type_2;
...
// использование:
int condition_key = (condition1 & CONDITION1_BIT)|(condition2 & CONDITION2_BIT)...;
MetaType *obj = creators[condition_key] ();

PM MAIL   Вверх
borisbn
Дата 12.9.2013, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



baldina, спасибо. Понял. Но у меня после создания экземпляра конкретного класса идёт ещё его инициализация - одинаковая для всех 4-х классов. В вашем примере:
Код
MetaType * createAs (EMetaType t) {
  switch (t) {
    case MType_1:
        Type_1 * t = new Type_1;
        t->field1 = 42;
        t-Юfield2 = "Hello world";
        return t;
    case MType_2:
        Type_2 * t = new Type_2;
        t->field1 = 42;                   // <--- вот этого повторения я и хотел избежать
        t->field2 = "Hello world";
        return t;
    ...
  }
}


В общем, пока сделал так:
Код
template< class T >
Base * createSnake( const Data & data ) {
    T * t = new T;
    t->head = data;
    t->body = data;
    t->tail = data;
    return t;
}
...
Data data;
Base * ptr = 0;
if ( condition ) {
    if ( sub_condition ) {
        ptr = createSnake< Type_1 >( data );
    }
    else {
        ptr = createSnake< Type_2 >( data );
    }
}
else {
    if ( sub_condition ) {
        ptr = createSnake< Type_3 >( data );
    }
    else {
        ptr = createSnake< Type_4 >( data );
    }
}

но и здесь мне не нравится copy-paste....

Цитата(baldina @  12.9.2013,  14:32 Найти цитируемый пост)
и закончить кодированием condition и sub_condition битовой маской, которую использовать в качестве ключа для соответствующей функции создания объекта

Хммм... интересно... надо подумать...


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
baldina
Дата 12.9.2013, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



без повторений
Код

MetaType * createAs (EMetaType t) {
  switch (t) {
    case MType_1: Type_1 * t = new Type_1; break;
    case MType_2: Type_2 * t = new Type_2; break;
    ...
  }
  t->field1 = 42;                   
  t->field2 = "Hello world";
  return t;
}

кстати, почему бы для инициализации не использовать конструктор?
PM MAIL   Вверх
akizelokro
Дата 12.9.2013, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



А что вы здесь делаете?
Прикурочьте указатель на функцию, которая (ые) вам 1, 2, 3, 4 будут возвращать.


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
borisbn
Дата 12.9.2013, 16:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(baldina @  12.9.2013,  15:12 Найти цитируемый пост)
без повторений

 smile  
Цитата(baldina @  12.9.2013,  15:12 Найти цитируемый пост)
 case MType_1: Type_1 * t = new Type_1; break;
...
 t->field1 = 42;    


Type_1 * t = new Type_1; находится внутри case'а и дальше не виден.

У базового класса нет field1 и field2. Они есть только у наследников. См. внимательно иерархию классов в самом первом сообщении.
Цитата(baldina @  12.9.2013,  15:12 Найти цитируемый пост)
кстати, почему бы для инициализации не использовать конструктор? 

В реальном проекте я не могу менять struct Snake

Цитата(akizelokro @  12.9.2013,  16:42 Найти цитируемый пост)
Прикурочьте указатель на функцию, которая (ые) вам 1, 2, 3, 4 будут возвращать. 

Не понял. Можете показать кодом ?

baldinaakizelokro, не могли бы вы кодировать в "моих" терминах - Base, Snake, Type_X и т.п., а то иногда непонятно, что вы предлагаете. Спасибо.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
baldina
Дата 12.9.2013, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата(borisbn @  12.9.2013,  16:58 Найти цитируемый пост)
У базового класса нет field1 и field2. Они есть только у наследников

для этого сойдет шаблонная функция

Код

struct Snake_1 : public Base {
 int field1;
 int field2;
};

struct Snake_2 : public Base {
 int field1;
 int field2;
};

template <typename T>
void setFields (T* obj, int f1, int f2) {
  obj->field1 = f1;
  obj->field2 = f2;
}

Base* createSnake (type) {
  switch (type) {
     case 1: { Snake_1* s = new Snake_1; setFields (s, x, y); return s; }
     case 2: { Snake_2* s = new Snake_2; setFields (s, x, y); return s; }
  }
}


Добавлено @ 18:32
или так:

Код

template <typename T>
T* create (int x, int y) {
  T* s = new T;
  s->field1 = x;
  s->field2 = y;
}

Base* createSnake (type) {
  switch (type) {
     case 1: return create<Snake_1> (x, y); 
     case 2: return create<Snake_2> (x, y); 
  }
}


Это сообщение отредактировал(а) baldina - 12.9.2013, 18:33
PM MAIL   Вверх
borisbn
Дата 12.9.2013, 18:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(baldina @  12.9.2013,  18:26 Найти цитируемый пост)
для этого сойдет шаблонная функция

теперь это практически не отличается от того, что было в самом первом сообщении  smile

Представьте, что мне нужно будет поменять сигнатуру функции setFields... В этом случае мне придётся исправлять её вызов в каждом case'е, а этого, как раз, мне и не хочется


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
baldina
Дата 12.9.2013, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



хоть тут копипаста получается поменьше, но таки да, есть такое. и никуда от этого не деться, т.к. каждый тип должен создаваться отдельно.
и функция инициализации, как бы она не выглядела, применяется к разным типам.
можно конечно в функцию инициализации передавать все значения одним параметром (в контейнере), но тут масса небольших технических проблем, и стоит ли такой огород городить, надо серьезно подумать.
PM MAIL   Вверх
akizelokro
Дата 12.9.2013, 18:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Код

int (*PF)(void) = NULL;

template < class T, class PF>
struct Snake: Base
{
    T head;
    T body;
    T tail;
    virtual int id() const { return PF(); };
}


int One() {return 1;};
....

typedef PF Type_1;

PF pf
if (condition)
  pf = One;


ну, что-то такое, в таком роде. Дальше надо смотреть, а я так и не понял, что надо то и от чего можно отходить, а что отбрасывать нельзя. Да и компилятор далеко. Но мне, почему не знаю, это шаблоны с константами нарвятся даже меньше, чем enum.

А идеологически, ИМХО, в языке только один метатип (указатели на функцию), да и со списками условий, а уж тем более констант по порядку, разбираются массивом этих указателей.


Это сообщение отредактировал(а) akizelokro - 12.9.2013, 18:58


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1228 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.