Вложенные шаблоны

Шаблоны могут быть вложенными в классы/структуры или в другие шаблоны классов/структур. Это же касается и объединений.

В разделе, посвященном Объединениям мы познакомились с возможностью "конвертировать" значения long в double и обратно без потери точности.

Теперь мы можем использовать шаблоны для написания универсального "конвертера" (TemplatesConverter.mq5). Шаблонный класс Converter имеет два параметра T1 и T2, обозначающих типы, между которыми будет производиться конвертация. Для записи значения по правилам одного типа и чтения по правилам другого нам снова потребуется объединение. Мы сделаем его также шаблоном (DataOverlay) с параметрами U1 и U2, и определим внутри класса.

Класс обеспечивает удобное преобразование за счет перегрузки операторов [], в реализации которых и производится запись и чтение полей объединения.

template<typename T1,typename T2>
class Converter
{
private:
   template<typename U1,typename U2>
   union DataOverlay
   {
      U1 L;
      U2 D;
   };
   
   DataOverlay<T1,T2data;
   
public:
   T2 operator[](const T1 L)
   {
      data.L = L;
      return data.D;
   }
   
   T1 operator[](const T2 D)
   {
      data.D = D;
      return data.L;
   }
};

Объединение используется для описания поля DataOverlay<T1,T2> data внутри класса. Мы могли бы напрямую использовать T1 и T2 в DataOverlay и не делать это объединение шаблоном. Но для демонстрации самого технического приема, параметры внешнего шаблона передаются во внутренний шаблон при генерации поля data. Внутри DataOverlay та же пара типов будет известна как U1 и U2 (в дополнение к T1 и T2).

Проверим шаблон в действии.

#define MAX_LONG_IN_DOUBLE       9007199254740992
   
void OnStart()
{
   Converter<double,ulongc;
   
   const ulong value = MAX_LONG_IN_DOUBLE + 1;
   
   double d = value// possible loss of data due to type conversion
   ulong result = d// possible loss of data due to type conversion
   
   Print(value == result); // false
   
   double z = c[value];
   ulong restored = c[z];
   
   Print(value == restored); // true
}