Предложение - кастинг структур от базовых к производным - страница 4

 
fxsaber:

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

Кстати, по поводу замысловатости и неочевидности.  Вот допустим берём тот макрос _C из вашей библиотеки, который вы использовали выше, и используем его повсеместно в нашем проекте.  Компилируем проект - и получаем ошибку в Вашей библиотеке:

'A' has objects and cannot be used as union member TypeToBytes.mqh 47 15

Допустим мы проверили и убедились, что A действительно имеет объекты. Какие дальнейшие действия, чтобы понять откуда был вызван этот макрос?  (а он вызывается из сотни мест)

А код был такой:

struct A { void* a; };

struct B { char a; };

// ...

void Somewhere()
{
  A a;
  B b;
  _C(A, b);
}
 
Alexey Navoykov:

Кстати, по поводу замысловатости и неочевидности.  Вот допустим берём тот макрос _C из вашей библиотеки, который вы использовали выше, и используем его повсеместно в нашем проекте.  Компилируем проект - и получаем ошибку в Вашей библиотеке:

Допустим мы проверили и убедились, что A действительно имеет объекты. Какие дальнейшие действия, чтобы понять откуда был вызван этот макрос?  (а он вызывается из сотни мест)

А код был такой:

Если делается замена в коде, то постепенно. Это как при написании каждого куска программы проверять его правильность. Ваш же метод - написать все куски, а потом проверять.

 


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

Предложение - кастинг структур от базовых к производным

pavlick_, 2019.01.21 15:39

Для простого обнаружения неверного вызова можно так (да, костыль и всё такое)

// comparable.mqh
//#define TCOMPARE_CHECK
#ifdef TCOMPARE_CHECK
   template<typename T>
   struct TComparable { 
      protected: TComparable() {}
      public:    int CompareTo(const T & obj) const { return obj.CompareTo(obj); }
   };
   #define TCOMPARABLE(T, VIS) : VIS TComparable<T>
   template<typename T>
   int Compare(const TComparable<T> &a, const TComparable<T> &b)  {Alert("TCOMPARE_CHECK mode !!!!!!!!!!!"); return 0; }
#else
   #define TCOMPARABLE(T, VIS)
   template<typename T>
   int Compare(const T &a, const T &b)  { return a.CompareTo(b); }
#endif
// end of comparable.mqh


struct A TCOMPARABLE(A, public)
{ 
  double a;
  A(double value) { a=value; }
  int CompareTo(const A & obj) const { return a>obj.a ? 1 : a<obj.a ? -1 : 0; }
};

void OnStart()
{
   //A a=10, b=20;
   int a=10, b=20;
   int result= Compare(a, b);
}

Когда получена ошибка и об отсутствующем члене и непонятно куда копать, делаем дефайн TCOMPARE_CHECK и получаем понятное 'a' - parameter conversion not allowed  в месте вызова с интом.


Кстати, спасибо за идею.  Я её взял на вооружение, немного подшаманил,  и получился более удобный и изящный вариант:

#define TCOMPARE_CHECK

template<typename T>
struct __TComparable { public: int CompareTo(const T & obj) const { return obj.CompareTo(obj); } };

#ifdef TCOMPARE_CHECK
   template<typename T>
   struct TComparable : public __TComparable<T> { protected: TComparable() {} };
   #define TCOMPARABLE_ARG(T) TComparable<T>
#else
   template<typename T>
   struct TComparable : private __TComparable<T> { protected: TComparable() {} };
   #define TCOMPARABLE_ARG(T) T
#endif


template<typename T>
int Compare(const TCOMPARABLE_ARG(T) &a, const TCOMPARABLE_ARG(T) &b) { return a.CompareTo(b); } 


struct A : TComparable<A> 
{ 
  double a;
  A(double value) { a=value; }
  int CompareTo(const A & obj) const { return a>obj.a ? 1 : a<obj.a ? -1 : 0; }
};


void OnInit()
{
  A a(10), b(20);
  Compare(a, b);
  
  int a_, b_;
  Compare(a_, b_);  // 'a_' - parameter conversion not allowed
}

Достаточно ещё немного пошаманить и можно сделать один универсальный макрос для любых интерфейсов.

Фактически это единственное рабочее решение для структур в MQL, позволяющее избежать оборачивание функций в макросы.

 
Alexey Navoykov:

получился более удобный и изящный вариант

Так и не понял, что хотелось получить?
 
Alexey Navoykov:

Вроде неплохо. Только отсутствие множественного наследования станет узким местом, наверное.

 
pavlick_:

Вроде неплохо. Только отсутствие множественного наследования станет узким местом, наверное.

Это да.  Но я давно пользуюсь альтернативным вариантом:  все интерфейсы изначально оформляю в виде промежуточного шаблонного класса:

template<typename T, typename TPARENT>
class IComparable_ : public TPARENT
{
 public: virtual int CompareTo(const T&) const = 0;
};

template<typename T, typename T2>
int Compare(const IComparable_<T, T2> & a, const IComparable_<T, T2> & b) { return a.CompareTo(b); }


class CBase {  };

class A : public IComparable_<A, CBase>
{
 public: int CompareTo(const A&) const;
};
Таким образом можно создавать цепочку наследования из любого числа таких интерфейсов.   Да, конечно dynamic_cast с ними не сделаешь, но это не такая уж и частая необходимость.  Главная задача - это передача в функции.
 
fxsaber:
Так и не понял, что хотелось получить?
Да забейте )  Это так, для особых гурманов.
Причина обращения: