crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

4 страниц V   1 2 3 > »   
Ответить в данную темуНачать новую тему
> Шаблон, динамическое значения параметра шаблона, параметр не является типом
ViGOur
  опции профиля:
сообщение 15.2.2013, 8:58
Сообщение #1


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Я создаю динамически объекты некоторых произвольных классов, родитель у них один, тип только разный.
Для вопроизведения ошибки набросал следующий код:
class CEnumClass
{
public:
    enum eEnum{
        P1,
        P2,
        P3
    };
};

template <class T, int TYPE>
class CClass
{
// ...
};

int main(int argc, char *argv[])
{
    CEnumClass::eEnum tmpEnum = CEnumClass::P1;
    const int n0 = 10;
    const int n1 = tmpEnum;

    CClass<int, 0> mc0;                // OK
    CClass<int, n0> mc1;              // OK
    CClass<int, CEnumClass::P1> mc2; // OK
    //CClass<int, n1> mc3;            // error: 'n1' cannot appear in a constant-expression
    //CClass<int, tmpEnum> mc4;  // error: 'tmpEnum' cannot appear in a constant-expression
}

В конструкции template <class T, int TYPE>, TYPE сделан для того, чтобы при инстанцировании различались типы объектов данного класса с задумкой на будущее... И данный тип передается динамически, во время выполнения программы. Тоесть, у меня из вне приходит некий tmpEnum, что в примере и я на основе него должен создать-получить объект mc4, но возникает ошибка указанная в коментарии при создании объекта mc4 .

Как я понимаю это из-за того, что у меня переменная создается динамически (во время выполнения), а шаблон должен быть инстанцирован статически (во время компиляции). Поправьте меня если я ошибаюсь.


И собственно вопрос, как сделать так, чтобы это работало и возможно ли это? :)
Если это не возможно, то буду думать как сделать по другому...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ssoft
  опции профиля:
сообщение 15.2.2013, 9:37
Сообщение #2


Участник
**

Группа: Участник
Сообщений: 130
Регистрация: 17.2.2010
Из: Москва
Пользователь №: 1470

Спасибо сказали: 30 раз(а)




Репутация:   3  


Цитата(ViGOur @ 15.2.2013, 9:58) *
Как я понимаю это из-за того, что у меня переменная создается динамически (во время выполнения), а шаблон должен быть инстанцирован статически (во время компиляции). Поправьте меня если я ошибаюсь.

И собственно вопрос, как сделать так, чтобы это работало и возможно ли это? :)
Если это не возможно, то буду думать как сделать по другому...


Имено так, шаблоны конкретизируются во время компиляции и нет возможности использовать динамически изменяющиеся параметры шаблона.
В данном случае, я подозреваю, что необходимо использовать паттерн "Фабрика".
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 10:19
Сообщение #3


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Боюсь паттерн Фабричный метод здесь не поможет, дело в том, что шаблонный класс реализован как синглтон, которому в качестве параметров передаются:
1. класс, объект которого нужно создать-получить.
2. некий внутренний тип, который явно идентифицирует объект, так как класс для некоего множества объектов может быть один, а тип у них разный...

Например:
class CAnimal{};
class CCat: CAnimal{};
class CDog: CAnimal{};

CAnimal *p1 = CSingleton<CCat, eMurka>::init
...
CAnimal *p2 = CSingleton<CDog, eVolk>::init();
CAnimal *p3 = CSingleton<CDog, ePudel>::init();
CAnimal *p4 = CSingleton<CDog, eTaksa>::init();
Пока вижу только не очень хороший выход в использовании ручной типизации, но это геморно и чревато ошибками... :(

Или я что-то не додумываю-недопонию?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 15.2.2013, 10:26
Сообщение #4


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


если это связано с типами, то тожно тупо в конструкторе передавать std::type_info. ну или вообще что угодно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 10:39
Сообщение #5


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Неа, в моем случае объекты p3 и p4 (ePudel и eTaksa) это разные типы, и так как они по разному инстанцируются, то и разные объекты.
Простая передача параметра в конструкторе не даст того же результата...

Например,
CAnimal *p3 = CSingleton<CDog, ePudel>::init();
CAnimal *p4 = CSingleton<CDog, eTaksa>::init();
CAnimal *p5 = CSingleton<CDog, ePudel>::init();
CAnimal *p6 = CSingleton<CDog, eTaksa>::init();
p5 == p3, а p6 == p4, но p5 != p6.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 15.2.2013, 11:20
Сообщение #6


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


имхо, виртуальное наследование спасёт )

class CDog
{
protected:
    virtual init()=0;
};


class CPudel:CDog
{
   init()
   {
   }
};

...

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 11:33
Сообщение #7


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Цитата(Алексей1153 @ 15.2.2013, 12:20) *
имхо, виртуальное наследование спасёт )
Это как я понимаю и есть фабричный метод!
Цитата(ViGOur @ 15.2.2013, 11:19) *
Боюсь паттерн Фабричный метод здесь не поможет, дело в том, что шаблонный класс реализован как синглтон, которому в качестве параметров передаются:
И если это реализовывать, то в моем случае класс CPudel, будет заботится о создании самого себя, в место шаблонного класса (который, как я писал уже выше, является синглтоном), а вместе с этим в нем нужно будет закрывать: конструктор, деструктор, конструктор копирования и оператор присваивания... А так же, если в моем зоопарке будет за 100500 зверей, то всем им нужно будет делать то же самое и описывать своё рождение!

Как-то не комильфо...

Звери тут в качестве примера и не более! :)

з.ы. или я все же не правильно понял идею вашей реализации.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 15.2.2013, 11:45
Сообщение #8


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Цитата(ViGOur @ 15.2.2013, 14:33) *
Это как я понимаю и есть фабричный метод!

нет, это возможности языка. Фабрика - это отдельный класс/процедура, которая порождает объекты по маркеру их типа и возвращает указатель типа "родитель"

синглтон можно сделать статическим методом родительского класса (синглтон Майерса)

а описывать разницу в поведении типов всё равно где-то придётся :)

можно все классы поместить в один namespace , тогда путаться ничего не будет
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 11:45
Сообщение #9


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Пока я вижу выход, как я уже говорил:
Цитата(ViGOur @ 15.2.2013, 11:19) *
Пока вижу только не очень хороший выход в использовании ручной типизации, но это геморно и чревато ошибками... :(
в использовании switch, например так:
switch(type)
{
 case P1: CClass<int, CEnumClass::P1> mc1;break;
 case P2: CClass<int, CEnumClass::P2> mc2;break;
 case P3: CClass<int, CEnumClass::P3> mc3;break;
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 15.2.2013, 11:47
Сообщение #10


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


и ещё - при отладке с шаблонами можно запариться, так как отладчик не сможет показать, какой именно сейчас тип у владельца процедуры

Цитата(ViGOur @ 15.2.2013, 14:45) *
в использовании switch,

этот код и будет находится в методе-фабрике

Сообщение отредактировал Алексей1153 - 15.2.2013, 11:47
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 11:51
Сообщение #11


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Цитата(Алексей1153 @ 15.2.2013, 12:47) *
этот код и будет находится в методе-фабрике
Ну это можно и без фабрики изобразить, по крайней мере в моей структуре кода! :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 15.2.2013, 11:53
Сообщение #12


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


ViGOur, я - за инкапсуляцию )))
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 12:07
Сообщение #13


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


да есть она там, но именно в данном случае она не нужна! :D
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 15.2.2013, 12:15
Сообщение #14


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


it's enough of encapsulation! No more! ))
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 14:20
Сообщение #15


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


ssoft, ты был прав, паттерн Фабричный метод самое то,единственное к нему понадобился плюс, в виде рекурсивного аргумента шаблона (это подсказал мне Flex_Ferrum) и все заработало!

Вот окончательный вариант с учетом моего примера:
class CEnumClass
{
public:
    enum eEnum{ P1, P2, P3, P_END };
};

template <class T, int I>
class CClass
{
public:
    static T *init(){ return new T; }
};

template<class T, int I>
class MyFactoryImpl;

template<class T, int I>
class MyFactoryImpl : public MyFactoryImpl<T, I - 1>
{
public:
   static T* create(int idx) { return idx == I ? CClass<T, I>::init() : MyFactoryImpl<T, I - 1>::create(idx); }
};

template<class T>
class MyFactoryImpl<T, 0>
{
public:
   static T* create(int idx) { return idx == 0 ? CClass<T, 0>::init() : 0; }
};

template<class T, int MaxI>
class MyFactory : MyFactoryImpl<T, MaxI - 1>
{
public:
   static T* create(int idx) { return MyFactoryImpl<T, MaxI - 1>::create(idx); }
};

int main(int argc, char *argv[])
{
    CEnumClass::eEnum tmpEnum = CEnumClass::P1;
    MyFactory<int, CEnumClass::P_END>::create(tmpEnum);

    return 0;
}


Сообщение отредактировал ViGOur - 19.2.2013, 16:53
Причина редактирования: Поправил, был старый вставил старый тест...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 15.2.2013, 14:55
Сообщение #16


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Изменил код, так как по невнимательности вставил код немного другого теста...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 15.2.2013, 18:25
Сообщение #17


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


занимательно вышло, кстати, с точки зрения брейнфака )

с точки зрения практики- хм... Потом расскажешь:)

Сообщение отредактировал Алексей1153 - 15.2.2013, 18:26
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 18.2.2013, 10:01
Сообщение #18


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


template <typename T>
CAnimal *class_creator () {
    return new T;
};

typedef CAnimal *CAnimalPtr;
typedef CAnimalPtr (*CreatorFunc) ();
const CreatorFunc creators = {class_creator<CMurka>, class_creator<CVolk>};

class CAnimal {
    static CAnimal *Instance (CEnumClass::eEnum type) {
        static std::map<CEnumClass::eEnum, CAnimal*> here_be_singletons;
        
        if (here_be_singletons.find (type) == here_be_singletons.end ()) {
            here_be_singletons[type] = creators[type] ();
            here_be_singletons[type]->init ();
        };
        
        return here_be_singletons[type];
    };
};

Какие подводные камни?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 18.2.2013, 12:12
Сообщение #19


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


1. Данный код только для класса CAnimal и производных от него классов. ( я понимаю, что можно поправить, но все же! :) )
2. При добавлении типа в CEnumClass::eEnum, тебе так же нужно будет добавлять прототип функции в массив creators. (если забыл добавить, то ... )
3. Ты должен будешь соблюдать порядок типов в CEnumClass::eEnum и прототипов функций в массиве creators. (если порядок другой, то ...)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 18.2.2013, 14:11
Сообщение #20


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


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

Чего то я не очень догоняю зачем их смешивать.
Как я понял, задача состоит в том чтобы сделать N различных типов.
А зачем? Все равно они будут использоваться через один и тот же интерфейс (CAnimal*).
А если это для того чтобы сделать статическую проверку типов, то все равно ничего не выйдет (та же проблема что и в первом посте).

Можно какой нибудь пример использования?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 18.2.2013, 15:09
Сообщение #21


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Цитата(lanz @ 18.2.2013, 15:11) *
Можно какой нибудь пример использования?
Легко, правда это не мой пример, долго объяснять, потому не буду, дам пример по проще, но суть будет примерно та же...

Пишется модуль по работе с протоколами, пускай они будут подключаться как плагины. На данный момент мы должны уметь подключать к нему такие протоколы как HTTP и FTP.
А если понадобиться позднее подключать SNMP. А еще позже SMTP, POP3, IMAP. А в конце концов скажут подключаем прикрутит еще чего, как ты будет закладываться на все это?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 18.2.2013, 16:47
Сообщение #22


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Можно так, с учетом пунктов 1, 3.
Вместо енума можно использовать текстовые идентификаторы например(или генерить на лету). Тогда и пт. 2 сильно не влияет.
В загрузку плагина не забудешь запихнуть регистрацию класса(а если и забудешь, легко ловится тестами).
А еще без перекомпиляции при изменении enuma ;)
Раскрывающийся текст
template<typename T, typename C>
C* class_creator () {
    return new T;
};

template<typename C>
class AbstractManager {
    typedef C* CPtr;
    typedef CPtr (*CreaFunc) ();
    static C *Instance () {
        static AbstractManager pm;
        return &pm;
    };
    C* create (int id) {
        return this->creators[id] ();
    };
    bool register_creator(int id, CreaFunc func) {
        return this->creators[id] = func;
    };
private:
    ctor/copy_ctor/dtor

    std::map<int, CreaFunc> creators;
};

class Protocol {
    virtual void send (char*) = 0;
    virtual void recv (char*) = 0;    
};

class HTTP : public Protocol {
    void send (char*) {...};
    void recv (char*) {...};    
};

// Вставляем либо через интерфейс плагинов
// Либо через трюк
bool registered = AbstractManager<Protocol>::Instance ()->
    register_creator (42, class_creator<HTTP, Protocol>);
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 19.2.2013, 10:08
Сообщение #23


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Честно говоря, ИМХО особо ничего не поменялось... :)

Мне вот вспомнилась задачка от яндекса, при тестировании знаний перед собеседованием:

Есть класс CodeGenerator, который умеет генерить код на разных языках.
class CodeGenerator
{
public:
    enum Lang {JAVA, C_PLUS_PLUS, PHP};
    CodeGenerator(Lang language) { _language=language; }
    std::string generateCode()
    {
        switch(_language) {
        case JAVA:        //return generated java code
        case C_PLUS_PLUS: //return generated C++ code
        case PHP:         //return generated PHP code
        }
        throw new std::logic_error("Bad language");
    }
    std::string someCodeRelatedThing() // used in generateCode()
    {
        switch(_language) {
        case JAVA:        //return generated java-related stuff
        case C_PLUS_PLUS: //return generated C++-related stuff
        case PHP:         //return generated PHP-related stuff
        }
        throw new std::logic_error("Bad language");
    }

private:
    Lang _language;
}

Исходя из предположения, что количество языков будет увеличиваться, предложите refactoring кода. Аргументируйте преимущество вашего кода над существующим. ( Оригинал )
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 19.2.2013, 11:50
Сообщение #24


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Цитата
1. Данный код только для класса CAnimal и производных от него классов. ( я понимаю, что можно поправить, но все же! )

Теперь шаблон.

Цитата
2. При добавлении типа в CEnumClass::eEnum, тебе так же нужно будет добавлять прототип функции в массив creators. (если забыл добавить, то ... )

Вместо этого регистрация (=1 действие), но тут никуда не дется, если берем за референс реализацию с рекурсивными шаблонами,
то там придется добавлять enum + делать полную специализацию CClass (=2 действия)
Два действия забыть проще .)

Цитата
3. Ты должен будешь соблюдать порядок типов в CEnumClass::eEnum и прототипов функций в массиве creators. (если порядок другой, то ...)

При регистрации порядок неважен.

В задаче от яндекса то же, только в профиль. Немного интересней, что зависимые от языка вещи находятся в двух местах, но это непринципиально, сюда тоже можно сунуть фабрику.
Плюсы - только уменьшеие количества мест, которые нужно исправить при переделке и как следствие повышение багоустойчивости.
Минусы - усложненная архитектура.
Вообще switch неплох, когда у нас участвует менее 6-7 элементов.
Поэтому при прочих равных, я бы максимум убрал второй switch.

Как то так.
Раскрывающийся текст
class CodeGenerator {
    virtual std::string generateCode () = 0;
    virtual std::string someCodeRelatedThing () = 0;
};

class JavaGenerator : public CodeGenerator {
    ...
}

class CodeGenFactory {
    CodeGenerator *create (Lang l) {
            switch (l) {
                case JAVA:
                    return new JavaGenerator;
                case C_PLUS_PLUS:
                    ...
            };
    };
};
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 19.2.2013, 16:25
Сообщение #25


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


знаешь, я вообще перечитала твою тему с начала и подумала, что я тут уже писала на этот счёт. только у меня задача сложнее была, с библиотеками, но смысл был совершенно тот же.
у меня была задача сделать плагины к существующему коду так, чтобы плагины было можно подцеплять отдельно, динамически, не трогая весь остальной код. и чтобы они наследовали общее поведение в некоторых методах.
http://www.forum.crossplatform.ru/index.php?showtopic=6472
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 19.2.2013, 16:52
Сообщение #26


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Да я уже сдела что хотел и вылодил описание как...
Просто lanz, предлагает свое решение, которое мне явно не подходит. :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 19.2.2013, 16:57
Сообщение #27


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Почему, ну почему-же не подходит?! :lol:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 19.2.2013, 20:56
Сообщение #28


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Цитата(lanz @ 19.2.2013, 17:57) *
Почему, ну почему-же не подходит?! :lol:
А вот почему:
"Код"
class CodeGenerator
{
public:
    enum Lang { JAVA, CPP, LANG_END };

    virtual void generateCode()=0;
    virtual void someCodeRelatedThing()=0;

protected:
    Lang _language;
};

template <int TYPE>
class langCodeGenerator : public CodeGenerator
{
};

template <>
class langCodeGenerator<CodeGenerator::JAVA> : public CodeGenerator
{
public:
    virtual void generateCode(){ qDebug() << "CodeGenerator::JAVA - generateCode"; }
    virtual void someCodeRelatedThing(){ qDebug() << "CodeGenerator::JAVA - someCodeRelatedThing"; }
};

template <>
class langCodeGenerator<CodeGenerator::CPP> : public CodeGenerator
{
public:
    virtual void generateCode(){ qDebug() << "CodeGenerator::CPP - generateCode"; }
    virtual void someCodeRelatedThing(){ qDebug() << "CodeGenerator::CPP - someCodeRelatedThing"; }
};

template<class T, int I>
class MyFactoryImpl;

template<class T, int I>
class MyFactoryImpl : public MyFactoryImpl<T, I - 1>
{
public:
   static T* instance(int idx) { return idx == I ? new langCodeGenerator<I> : MyFactoryImpl<T, I - 1>::instance(idx); }
};

template<class T>
class MyFactoryImpl<T, 0>
{
public:
   static T* instance(int idx) { return idx == 0 ? new langCodeGenerator<0> : 0; }
};

template<class T, int MaxI>
class MyFactory : MyFactoryImpl<T, MaxI - 1>
{
public:
   static T* instance(int idx) { return MyFactoryImpl<T, MaxI - 1>::instance(idx); }
};

void generate(CodeGenerator::Lang lang)
{
    CodeGenerator *p = MyFactory<CodeGenerator, CodeGenerator::LANG_END>::instance(lang);
    if( p )
    {
        p->generateCode();
        p->someCodeRelatedThing();
        delete p;
        p=0;
    }
}

int main(int , char **)
{
    for( int n = CodeGenerator::JAVA; n < CodeGenerator::LANG_END; ++n )
        generate( (CodeGenerator::Lang)n );

    return 0;
}
И если вдруг понадобится мне добавить дополнительный язык (например Python), то мне нужно будет:
1. добавить его в enum Lang перед LANG_END.
2. добавить специализацию шаблона langCodeGenerator для него:
template <>
class langCodeGenerator<CodeGenerator::PYTHON> : public CodeGenerator
{
public:
    virtual void generateCode(){ qDebug() << "CodeGenerator::PYTHON - generateCode"; }
    virtual void someCodeRelatedThing(){ qDebug() << "CodeGenerator::PYTHON - someCodeRelatedThing"; }
};
И не более того! ;)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 20.2.2013, 9:14
Сообщение #29


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Ну да, но если сравнивать:
Раскрывающийся текст
class Python : public CodeGenerator {
    virtual void generateCode(){ qDebug() << "CodeGenerator::Python - generateCode"; }
    virtual void someCodeRelatedThing(){ qDebug() << "CodeGenerator::Python - someCodeRelatedThing"; }
};

int main (int, char**) {
    // Оверхед! xD
    AbstractManager<CodeGenerator>::Instance ()->
        register_creator (Lang::Python, class_creator<Python, CodeGenerator>);
    
    CodeGenerator *py = AbstractManager<CodeGenerator>::Instance()->create (Lang::Python);    
    
    return 0;
};

Минусы - оверхед на регистрацию + оверхед на хранение,
если забыть зарегистрировать - ничего не заработает (будет ошибка времени выполнения, а не времени компиляции),
слишком усложненное использование для небольшого числа объектов.
Плюсы - читается лучше(при всей моей любви к шаблонам, рекурсивные шаблоны - это "особая шаблонная магия"),
не надо перекомпилировать все классы языков при добавлении нового (это кстати позволит разнести их по дллкам например и загружать динамически),
в вашем решении каждый вызов instance будет рекурсивным и пробегатся по всей иерархии шаблонов (т.е. получится тот же switch, только "размазанный по коду".
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 20.2.2013, 9:47
Сообщение #30


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Со всем в принципе согласен, но как я уже говорил под мои нужды это самое то!
У меня уже за 20 разных объектов в enum'е и думается мне их прибавится! И если что-то не так, то лучше узнать об этом на этапе компиляции... :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 20.2.2013, 10:02
Сообщение #31


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Конечно надо использовать то что лучше подходит, каждый случай уникален! :lol:
Просто мне и самому хотелось поподробнее плюсы и минусы разобрать, а то этот метод уже в идиому для меня превратился.
Ну и кроме того теперь буду использовать шаблонный class_creator и фабрику вместо того чтобы для каждого нового класса писать свой 8)
Спасибо за содержательный диалог!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

4 страниц V   1 2 3 > » 
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 16.7.2025, 17:48