crossplatform.ru

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

4 страниц V  < 1 2 3 4 >  
Ответить в данную темуНачать новую тему
> Шаблон, динамическое значения параметра шаблона, параметр не является типом
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'е и думается мне их прибавится! И если что-то не так, то лучше узнать об этом на этапе компиляции... :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 24.4.2024, 8:11