Russian Qt Forum
Май 03, 2024, 20:55 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Пустая структура  (Прочитано 8442 раз)
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #15 : Ноябрь 03, 2014, 14:06 »

Не вижу где я ошибаюсь

В том примере используется информация о типе (название типа), но не используются объекты этого типа (объекты типов-пустышок нигде не использовались. Вообще не были созданы).

А в этом случае, вам достаточно лишь forward declaration.
А вот определение типа - избыточно.

Пример:

http://rextester.com/RQSPH39005



Код:
#include <iostream>

struct Example
{
    template<class T> Example(const T& src)   //<--- T может быть либо int, либо float
    {
        enum { eIS_INT   = ::std::is_same<T, int>::value   };
        enum { eIS_FLOAT = ::std::is_same<T, float>::value };
        enum { eIS_VALID = eIS_FLOAT || eIS_INT };
        
        static_assert(eIS_VALID, "SORRY, BUT TYPE MUST BE INT OR FLOAT. OTHER TYPES NOT SUPPORT");
        
        typedef typename ::std::conditional<eIS_INT,   //<--- В зависимости от T выбирается стратегия его обработки
                    StrategyInt, StrategyFloat          
                >::type
            Strategy;
        
        Process( (Strategy*)nullptr );  //<--- типы-тэги нужны лишь для ручного управления выбором
                                        //      перегруженной функции-члена Process
                                        //    сами же объекты типов-тэгов нам не нужны
        
    }
private:
    struct StrategyInt;    //<--- поскольку объекты типов-тэгов нам не нужны,
    struct StrategyFloat;  // то мы вообще не делаем туловища для этих типов

    
    void Process(const StrategyInt*)                   //<--- forward declaration вполне достаточно,
    {                                                  //что бы контролировать выбор перегруженных функций
        ::std::cout<<" selected strategy for int\n";   //и что бы контролировать процесс инстанцирования шаблонов,
    }                                                  //и для любых других задач, где тип используется для ветвлений алгоритмов
    void Process(const StrategyFloat*)                
    {
        ::std::cout<<" selected strategy for float\n";
    }
};

int main()
{
    std::cout << "Hello, world!\n";
    
    Example(10);
    Example(10.5f);
}

Пример конечно утрирован, сферический конь в ваккуме. Но бывают задачи, когда выбор стратегии дальнейших действий - штука не тривиальная. Где то в шаблонах в зависимости от свойств каких то типов выбирается нечто.

В таких случаях типы-тэги помогают упростить конструкцию, выполнить развилку алгоритма, определить какие то стратегии.
----------------------

Ситуация, когда вам не нужны объекты пустышки, и вы можете полностью сохранить и идею использования и реализацию без использования объектов типов-тэгов, это примеры-иллюстрации использования forward-declaration, а вовсе не пример использования типов-пустышек.

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


Под извлечением имелась ввиду "инстанциация"? Но ведь ф-ция не template. Непонятно, объясните.
Спвсибо

Под "извлечением" подразумевалось "извлечение".

Здесь нужно немножко понимать, как работает механизм Arg.

Иногда бывают задачи, когда позарез хочется что бы шаблонная функция могла быть виртуальной.

Код:
virtual foo(  const T& source_data );

К сожалению, сделать это не возможно.

И тогда самое простое и сердитое решение: использовать универсальный тип данных:

Код:
virtual foo(  const void* source_data );

Это будет работать. Но это не надежно, потому что  теряется контроль за типами аргументов.

Вот если бы было тоже самое, но с сохранением проверок типов и квалификаторов...

И тогда на сцену выходит механизм Arg.
Он запоминает ссылки на аргументы любых типов, и выполняет проверки типов и квалификаторов.

Причем доступен режим, при котором в релизе все проверки будут удалены. И получится тот же самый void*.
А есть режимы, когда он будет постоянно кидаться ассертами, или исключениями.

Область применения Arg - аргументы функций в условиях, когда заранее не известны ни их типы, ни их количество.


Изначально, я разработал механизм Arg, что бы с его помощью построить динамический делегат:


Код:
sample obj;
Connector con( obj, &sample::foo ); //<--- нацеливание делегата на функцию-член

con(10,20); //<--- запуск. Эквивалентен: obj.foo(10,20)

В отличие от статических делегатов,
таких как TConnector или std::function, динамический Connetor не является продуктом шаблона.

Это обычный класс. Весьма простой в использовании.
Он умеет нацеливаться на любые функци, функции-члены, функторы времени выполнения.

В этой ситуации в статике невозможно предсказать на какие функции он будет нацелен, и какие там будут аргументы.
Поэтому, возникла необходимость использовать механизм Arg для контроля за количеством и типами аргументов, с которыми пользователь хочет выполнить запуск делегата.
« Последнее редактирование: Ноябрь 03, 2014, 14:15 от _Bers » Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #16 : Ноябрь 03, 2014, 14:07 »

По-моему, самое очевидный пример использования таких структур/классов - в обработке исключений.

Очевидный юзкейс исключений - наследоваться от std::exception.

Использование же пустышок для этих целей - не очевидный, и не профессиональный ход.
« Последнее редактирование: Ноябрь 03, 2014, 14:11 от _Bers » Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.048 секунд. Запросов: 23.