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) Link
Можно какой нибудь пример использования?
Легко, правда это не мой пример, долго объяснять, потому не буду, дам пример по проще, но суть будет примерно та же...

Пишется модуль по работе с протоколами, пускай они будут подключаться как плагины. На данный момент мы должны уметь подключать к нему такие протоколы как 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 кода. Аргументируйте преимущество вашего кода над существующим. ( Link )
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
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  


знаешь, я вообще перечитала твою тему с начала и подумала, что я тут уже писала на этот счёт. только у меня задача сложнее была, с библиотеками, но смысл был совершенно тот же.
у меня была задача сделать плагины к существующему коду так, чтобы плагины было можно подцеплять отдельно, динамически, не трогая весь остальной код. и чтобы они наследовали общее поведение в некоторых методах.
Link
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
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) Link
Почему, ну почему-же не подходит?! :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 Рейтинг@Mail.ru Текстовая версия Сейчас: 11.8.2025, 12:01