Особенности языка mql5, тонкости и приёмы работы - страница 98

fxsaber
16189
fxsaber  
TheXpert:

а смысл? сэкономить пару байт памяти? тем более с double получатся другие числа (== будет false)

Никакого смысла. Конструкция понравилась, не встречал ранее.

TheXpert
18188
TheXpert  
fxsaber:

Никакого смысла. Конструкция понравилась, не встречал ранее.

а, ок. через xor изящней, имхо

fxsaber
16189
fxsaber  
TheXpert:

а, ок. через xor изящней, имхо

Согласен

#define SWAP(A, B) { A ^= B; B ^= A; A ^= B; }


ЗЫ

#define SWAP(A, B) A ^= (B ^= (A ^= B));


Из Вики

Однако на современных ЦП XOR-техника значительно медленнее, чем использование временной переменной для обмена. Это происходит по причине распараллеливания выполнения команд. В XOR-технике операнды всех команд зависят от результатов предыдущих команд, поэтому они должны быть выполнены в строго последовательном порядке. В каждом конкретном случае рекомендуется протестировать скорости обеих альтернатив на целевой архитектуре.

Алексей Тарабанов
9561
Алексей Тарабанов  
Кошмар. 
Taras Slobodyanik
35106
Taras Slobodyanik  
fxsaber:

Из Вики

а если распараллелят предыдущие сложения/вычитания? )

fxsaber
16189
fxsaber  
Taras Slobodyanik:

а если распараллелят предыдущие сложения/вычитания? )

Не параллелится алгоритм, зависящий от последовательности действий. 

Алгоритм с временной переменной не является таким, поэтому параллелится.

Алексей Тарабанов
9561
Алексей Тарабанов  
Не-а...
fxsaber
16189
fxsaber  

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Ошибки, баги, вопросы

Ilyas, 2016.08.24 11:08

В массиве ("внутри") хранится allocated - под сколько элементов массив распределён.

Логика работы с резервом(условный код):
ArrayResize(arr,int size,int reserve)
  {
   if(arr.allocated<size)
      if(!ArrayAllocateMemory(arr,size+reserve))  // -> arr.allocated=size+reserve;
         return(-1);
   //---
   CallConstructorsOrDestructors(arr,size);
   //---
   arr.size=size;
   return(size);
  }
Alexey Navoykov
4552
Alexey Navoykov  

Продолжаем нашу рубрику "очумелые ручки".  Тема сегодняшней программы - шаблонная лихорадка, или как избавить себя от шаблона в заднице )

Часто возникает необходимость передать какую-то переменную в качестве шаблонного аргумента по ссылке для её модификации.  Однако спецификация шаблонов, к сожалению, не позволяет явно указать неконстантность аргумента, как это происходит в обычных функциях:

void Modify(int&) { }  // Принимает только не константы

template<typename T>
void Modify(T& a) {  } // Принимает любые аргументы

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

template<typename T>
void f0(T& a)  { a=10; }  // 'a' - constant cannot be modified

template<typename T>
void f1(T& a)  { f0(a); }

template<typename T>
void f2(T& a)  { f1(a); }

void Source() { const int a=0;  f2(a); }

В нормальных IDE это не является проблемой. Например VS отображает полную трассировку шаблонного маршрута, поэтому достаточно щёлкнуть в нужное место и сразу попадёшь куда надо.  А вот в MQL беда. Которая может стать постоянной головной болью шаблонщика.

Но всё поправимо. Для этого можно воспользоваться перегрузкой шаблонов:

template<typename T>
void Modify(const T&); // Фэйковый запрещённый шаблон

template<typename T>
void Modify(T& a) { a=10; }

Теперь при попытке передачи константы будет вызываться верхний шаблон. А т.к. он не определён, то выдаётся ошибка.  Но это недостаточное решение, т.к во-первых, ошибка возникает только при компиляции исполняемого модуля (а в .mqh не выдаётся), и во-вторых, эта ошибка возникает по месту объявления шаблона, а не по месту его вызова, которое мы хотим обнаружить.  Поэтому идём дальше.

В случае, когда шаблон является методом класса, всё просто: помещаем фэйковый шаблон в приватную секцию, и при попытке вызова получим ошибку доступа.

В случае же обычной функции - сложнее.  В С++ данную задачу не решить одними лишь перегрузками, требуется дополнительный функционал, которого нет в MQL.  Но тут нам на помощь приходит мощное оружие MQL - баги! )  В данном случае один из таких багов оказывается нам очень полезен  )
Добавляем в наш фэйковый шаблон дополнительный параметр T2.  И теперь при попытке вызова неправильного шаблона получаем ошибку по месту вызова:

template<typename T, typename T2>
void Modify(const T&);  // Запрещаем

template<typename T>
void Modify(T& a) { a=10; }

void Source()
{ 
  int a, const b=0;
  Modify(a);  // всё ОК
  Modify(b);  // template mismatch
}

Задача решена. В C++ разумеется в обоих случаях будет вызван нижний шаблон, т.к. там нет такого бага.

Данный способ может пригодится и ещё в одном случае:  при необходимости чёткого контроля типов аргументов функции, запретив неявное приведение.
Например, функция должна принимать только аргумент datetime, блокируя всякие int и прочее.
Делаем соответствующий вариант:

template<typename T, typename T2>
void MyFunc(T);  // Запрещаем

void MyFunc(datetime time) {  }

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

Я кстати для datetime всегда делаю такой запрет.  Считаю, зря разработчики вообще разрешили неявное приведение к нему, да ещё и без всяких предупреждений компилятора (за исключением лонга и стринга). Даже любой енум свободно приводится к нему без предупреждений.

Бывает и обратная задача:  запретить только вызов какого-то определённого типа. Решение будет аналогичным:

template<typename T,typename T2>
void MyFunc(datetime);  // Запрещаем

template<typename T>
void MyFunc(T arg) {  }


Как уже сказано выше, внутри класса всё решается и без лишних параметров.

fxsaber
16189
fxsaber  
Alexey Navoykov:

Продолжаем нашу рубрику "очумелые ручки".  Тема сегодняшней программы - шаблонная лихорадка, или как избавить себя от шаблона в заднице )

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

Возникает необходимость передать по ссылке без модификации - для скорости, либо же объект.

Однако существующая спецификация шаблонов C++, к сожалению, не позволяет явно указать неконстантность аргумента, как это происходит в обычных функциях:

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

Есть реальный пример в MQL5, когда возникает эта проблема?

В нормальных IDE это не является проблемой. Например VS отображает полную трассировку шаблонного маршрута, поэтому достаточно щёлкнуть в нужное место и сразу попадёшь куда надо.  А вот в MQL беда. Которая может стать постоянной головной болью шаблонщика.

Но всё поправимо. Для этого можно воспользоваться перегрузкой шаблонов:

Теперь при попытке передачи константы будет вызываться верхний шаблон. А т.к. он не определён, то выдаётся ошибка.  Но это недостаточное решение, т.к во-первых, ошибка возникает только при компиляции исполняемого модуля (а в .mqh не выдаётся), и во-вторых, эта ошибка возникает по месту объявления шаблона, а не по месту его вызова, которое мы хотим обнаружить.  Поэтому идём дальше.

В случае, когда шаблон является методом класса, всё просто: помещаем фэйковый шаблон в приватную секцию, и при попытке вызова получим ошибку доступа.

В случае же обычной функции - сложнее.  Синтаксически в С++ данная задача вообще не решаема, насколько я понял. Однако тут нас выручает то, что MQL - это не С++.  В нём есть баги )  И в данном случае эти баги можно обернуть во благо )

Добавляем в наш фэйковый шаблон дополнительный параметр T2.  И теперь при попытке вызова неправильного шаблона получаем ошибку по месту вызова:

Задача решена. В C++ разумеется в обоих случаях будет вызван нижний шаблон.

Реального примера удобства не хватает.

Данный способ может пригодится и ещё в одном случае:  при необходимости чёткого контроля типов аргументов функции, запретив неявное приведение.
Например, функция должна принимать только аргумент datetime, блокируя всякие int и прочее.
Делаем соответствующий вариант:

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

Это, вроде, вовсю используется в MQL5, как только появилась возможность. Если правильно понимаю, то это стандарт.

Я кстати для datetime всегда делаю такой запрет.  Считаю, зря разработчики вообще разрешили неявное приведение к нему, да ещё и без всяких предупреждений компилятора (за исключением лонга и стринга). Даже любой енум свободно приводится к нему без предупреждений.

Бывает и обратная задача:  запретить только вызов какого-то определённого типа. Решение будет аналогичным:

Испытываю удобство, что datetime ведет себя так, как сейчас. Когда проблема?


В целом очень хороший и нужный пост, Спасибо!