Такой код, наверное, может помочь, когда очень замысловато что-то написано и совсем не очевидно распутать последовательность шаблонов, макросов и специализаций.
Кстати, по поводу замысловатости и неочевидности. Вот допустим берём тот макрос _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);
}
Кстати, по поводу замысловатости и неочевидности. Вот допустим берём тот макрос _C из вашей библиотеки, который вы использовали выше, и используем его повсеместно в нашем проекте. Компилируем проект - и получаем ошибку в Вашей библиотеке:
Допустим мы проверили и убедились, что A действительно имеет объекты. Какие дальнейшие действия, чтобы понять откуда был вызван этот макрос? (а он вызывается из сотни мест)
А код был такой:
Если делается замена в коде, то постепенно. Это как при написании каждого куска программы проверять его правильность. Ваш же метод - написать все куски, а потом проверять.
Для простого обнаружения неверного вызова можно так (да, костыль и всё такое)
// 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 !!!!!!!!!!!"); return0; }
#else
#define TCOMPARABLE(T, VIS)
template<typename T>
int Compare(const T &a, const T &b) { return a.CompareTo(b); }
#endif
// end of comparable.mqhstruct 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; }
};
voidOnStart()
{
//A a=10, b=20;int a=10, b=20;
int result= Compare(a, b);
}
Когда получена ошибка и об отсутствующем члене и непонятно куда копать, делаем дефайн TCOMPARE_CHECK и получаем понятное 'a' - parameter conversion not allowed в месте вызова с интом.
Кстати, спасибо за идею. Я её взял на вооружение, немного подшаманил, и получился более удобный и изящный вариант:
Вроде неплохо. Только отсутствие множественного наследования станет узким местом, наверное.
Это да. Но я давно пользуюсь альтернативным вариантом: все интерфейсы изначально оформляю в виде промежуточного шаблонного класса:
template<typename T, typename TPARENT>
class IComparable_ : public TPARENT
{
public: virtualint 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 с ними не сделаешь, но это не такая уж и частая необходимость. Главная задача - это передача в функции.
Такой код, наверное, может помочь, когда очень замысловато что-то написано и совсем не очевидно распутать последовательность шаблонов, макросов и специализаций.
Кстати, по поводу замысловатости и неочевидности. Вот допустим берём тот макрос _C из вашей библиотеки, который вы использовали выше, и используем его повсеместно в нашем проекте. Компилируем проект - и получаем ошибку в Вашей библиотеке:
'A' has objects and cannot be used as union member TypeToBytes.mqh 47 15
Допустим мы проверили и убедились, что A действительно имеет объекты. Какие дальнейшие действия, чтобы понять откуда был вызван этот макрос? (а он вызывается из сотни мест)
А код был такой:
Кстати, по поводу замысловатости и неочевидности. Вот допустим берём тот макрос _C из вашей библиотеки, который вы использовали выше, и используем его повсеместно в нашем проекте. Компилируем проект - и получаем ошибку в Вашей библиотеке:
Допустим мы проверили и убедились, что A действительно имеет объекты. Какие дальнейшие действия, чтобы понять откуда был вызван этот макрос? (а он вызывается из сотни мест)
А код был такой:
Если делается замена в коде, то постепенно. Это как при написании каждого куска программы проверять его правильность. Ваш же метод - написать все куски, а потом проверять.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Предложение - кастинг структур от базовых к производным
pavlick_, 2019.01.21 15:39
Для простого обнаружения неверного вызова можно так (да, костыль и всё такое)
Когда получена ошибка и об отсутствующем члене и непонятно куда копать, делаем дефайн TCOMPARE_CHECK и получаем понятное 'a' - parameter conversion not allowed в месте вызова с интом.
Кстати, спасибо за идею. Я её взял на вооружение, немного подшаманил, и получился более удобный и изящный вариант:
Достаточно ещё немного пошаманить и можно сделать один универсальный макрос для любых интерфейсов.
Фактически это единственное рабочее решение для структур в MQL, позволяющее избежать оборачивание функций в макросы.
получился более удобный и изящный вариант
Вроде неплохо. Только отсутствие множественного наследования станет узким местом, наверное.
Вроде неплохо. Только отсутствие множественного наследования станет узким местом, наверное.
Это да. Но я давно пользуюсь альтернативным вариантом: все интерфейсы изначально оформляю в виде промежуточного шаблонного класса:
Таким образом можно создавать цепочку наследования из любого числа таких интерфейсов. Да, конечно dynamic_cast с ними не сделаешь, но это не такая уж и частая необходимость. Главная задача - это передача в функции.Так и не понял, что хотелось получить?