Writing generic code in MQL for Objects [solved]

 

[Solution]

Simple and direct answer:

https://www.mql5.com/en/forum/449290/page6#comment_48694920

Full development file:

https://www.mql5.com/en/forum/449290/page5#comment_47891500

A second approach to a solution:

https://www.mql5.com/en/forum/452570

____________



I have been working on unified functionality for types to be passed to a member function.

but for some reason I am not able to make it compile, has anyone an idea how to change the function signatures/template parameters so that this compiles.


struct my_rates_close : public MqlRates
{
    // Default constructor
    my_rates_close()                                        {};

    // Copy constructors
    my_rates_close(const MqlRates& p_in)                    { this = p_in; };

    // Operators
    const bool operator> (const my_rates_close& obj) const  { return(close > obj.close); };
};


static int serial = 1;
class test_obj
{
    public:
    int value;
    
    test_obj() :
        value (serial++)
    { };
    
    test_obj(const test_obj& p_in) :
        value (p_in.value)
    { };

    test_obj(const test_obj* p_in) :
        value (p_in.value)
    { };

    const bool operator> (const test_obj& p_in) const { return(value > p_in.value); };
};



template <typename T>
struct __test
{
    T value;
    __test() 
    { ZeroMemory(value); };

    template <typename U>
    const bool func(U*& p_in[])
    {
        T tmp = p_in[0];
        return(tmp > value);
    };

    template <typename U>
    const bool func(const U& p_in[])
    {
        T tmp = p_in[0];
        return(tmp > value);
    };

    template <typename U>
    const bool func(const U& p_in)
    {
        T tmp = p_in;
        return(tmp > value);
    };

    template <typename U>
    const bool func(U p_in)
    {
        T tmp = p_in;
        return(tmp > value);
    };
};



void OnStart()
{

    test_obj        t_obj;
    const test_obj  ct_obj;
    test_obj*       p_obj   = new test_obj();
    const test_obj* cp_obj = NULL;
    test_obj        t_obj_arr[2];
    test_obj*       p_obj_arr[2] = { new test_obj(), new test_obj() };
    MqlRates        rate_arr[2];
    MqlRates        rate;
    const MqlRates  c_rate;
    int             i_arr[2];
    const int       ci_v = 5;
    int             i_v = 3;

    __test<test_obj>        t_c();
    __test<test_obj*>       t_p();
    __test<my_rates_close>  t_o();
    __test<int>             t_int();

    t_c.func(t_obj);
    t_c.func(ct_obj);
    t_c.func(t_obj_arr);
    t_c.func(p_obj);
    t_c.func(cp_obj);
    t_c.func(p_obj_arr);

    t_p.func(t_obj);
    t_p.func(t_obj_arr);
    t_p.func(p_obj);
    t_p.func(p_obj_arr);

    t_o.func(rate_arr);
    t_o.func(rate);
    t_o.func(c_rate);

    t_int.func(3);
    t_int.func(i_v);
    t_int.func(ci_v);
    t_int.func(i_arr);

    delete(p_obj);
}


I dont know why this does not work with "const int" parameter types, as it does work with const >struct< and const >class< and const >class<* <- pointer

 

You have been here long enough to know that when you post code that does not compile, you should post the error log and identify which lines are erroneous.

 
Fernando Carreiro #:

You have been here long enough to know that when you post code that does not compile, you should post the error log and identify which lines are erroneous.

Ups... - I forgot to give these details. I was so focused on the error itself.


This line is giving an error as shown in following log

    t_int.func(ci_v);



 
Dominik Christian Egert:

I have been working on unified functionality for types to be passed to a member function.

but for some reason I am not able to make it compile, has anyone an idea how to change the function signatures/template parameters so that this compiles.



I dont know why this does not work with "const int" parameter types, as it does work with const >struct< and const >class< and const >class<* <- pointer

Because it's ambiguous, as struct and class can only be passed by reference.

Building true generic code with mql is currently not possible unfortunately.

 
Alain Verleyen #:

Because it's ambiguous, as struct and class can only be passed by reference.

Building true generic code with mql is currently not possible unfortunately.

But why is it only "const int" that's not working?

EDIT:

When I change the template to this, it stays the same...

template <typename T>
struct __test
{
    T value;
    __test() 
    { ZeroMemory(value); };

    template <typename U>
    const bool func(U*& p_in[])
    {
        T tmp = p_in[0];
        return(tmp > value);
    };

    template <typename U>
    const bool func(const U& p_in[])
    {
        T tmp = p_in[0];
        return(tmp > value);
    };

    template <typename U>
    const bool func(const U& p_in)
    {
        T tmp = p_in;
        return(tmp > value);
    };

    template <typename U>
    const bool func(const U p_in)
    {
        T tmp = p_in;
        return(tmp > value);
    };

    template <typename U>
    const bool func(U* p_in)
    {
        T tmp = p_in;
        return(tmp > value);
    };
};

 

Well, after some doubts...

You mean among the t_int call ?

    t_int.func(3);      // it's a literal, can't be a reference or an array, so only last version (4th from original code) match
    t_int.func(i_v);    // it's an int, not a const, not an array, only the last (4th from original code) one match
    t_int.func(ci_v);   // it's a const int, could be the third or last version (no idea why the version with array are also in the list of "could be")
    t_int.func(i_arr);  // it's an array, no pointer, so can only be the second (EDITED) version.
 
Alain Verleyen #:

Well, after some doubts...

You mean among the t_int call ?

I see... Need to think about this.

Edit: if it doesn't find a match, it always lists all possible functions
 
Dominik Christian Egert #:
I see... Need to think about this.

Edit: if it doesn't find a match, it always lists all possible functions

That's not exact.

   t_int.func(ci_v);
   t_int.func<const int>(ci_v);


 
Dominik Christian Egert #:
I see... Need to think about this.

Actually the "const" is not considered in the type, except for a reference (I had to make some checking to come to this conclusion).

  void OnStart()
  {
   int v1 = 7;
   const int v2 = 8;

   CheckTemplateTypeByValue(v1);
   CheckTemplateTypeByValue(v2);
   CheckTemplateTypeByReference(v1);
   CheckTemplateTypeByReference(v2);
}
template <typename T>
const void  CheckTemplateTypeByValue(T value)
  {
   Print(__FUNCSIG__," ",typename(T));
  }

template <typename T>
const void  CheckTemplateTypeByReference(T &value)
  {
   Print(__FUNCSIG__," ",typename(T));
  }

I am suggesting your to check with the variation "const T".

 
Alain Verleyen #:

Actually the "const" is not considered in the type, except for a reference (I had to make some checking to come to this conclusion).

I am suggesting your to check with the variation "const T".

I tried to understand how this is processed by the compiler and here is what I have found:

struct my_rates_close : public MqlRates
{
    // Default constructor
    my_rates_close()                                        {};

    // Copy constructors
    my_rates_close(const MqlRates& p_in)                    { this = p_in; };

    // Operators
    const bool operator> (const my_rates_close& obj) const  { return(close > obj.close); };
};


static int serial = 1;
class test_obj
{
    public:
    int value;
    
    test_obj() :
        value (serial++)
    { };
    
    test_obj(const test_obj& p_in) :
        value (p_in.value)
    { };

    test_obj(const test_obj* p_in) :
        value (p_in.value)
    { };

    const bool operator> (const test_obj& p_in) const { return(value > p_in.value); };
};



template <typename T>
struct __test
{
    T value;

    __test() 
    { ZeroMemory(value); };


    template <typename U>
    const bool func(U* p_in, const int line, const string param_type)
    {
        Print("LINE:", __LINE__, " Called from line: ", line, " - ", __FUNCSIG__, " >>>T: ", typename(T), "<<< - >>>U: ", typename(U), "<<< - >>> ParamType: ", param_type, " <<<");
        T tmp = p_in;
        return(tmp > value);
    };

    template <typename U>
    const bool func(U*& p_in[], const int line, const string param_type)
    {
        Print("LINE:", __LINE__, " Called from line: ", line, " - ", __FUNCSIG__, " >>>T: ", typename(T), "<<< - >>>U: ", typename(U), "<<< - >>> ParamType: ", param_type, " <<<");
        T tmp = p_in[0];
        return(tmp > value);
    };

    template <typename U>
    const bool func(const U& p_in[], const int line, const string param_type)
    {
        Print("LINE:", __LINE__, " Called from line: ", line, " - ", __FUNCSIG__, " >>>T: ", typename(T), "<<< - >>>U: ", typename(U), "<<< - >>> ParamType: ", param_type, " <<<");
        T tmp = p_in[0];
        return(tmp > value);
    };

    template <typename U>
    const bool func(U& p_in, const int line, const string param_type)
    {        
        Print("LINE:", __LINE__, " Called from line: ", line, " - ", __FUNCSIG__, " >>>T: ", typename(T), "<<< - >>>U: ", typename(U), "<<< - >>> ParamType: ", param_type, " <<<");
        T tmp = p_in;
        return(tmp > value);
    };

    template <typename U>
    const bool func(U p_in, const int line, const string param_type)
    {
        Print("LINE:", __LINE__, " Called from line: ", line, " - ", __FUNCSIG__, " >>>T: ", typename(T), "<<< - >>>U: ", typename(U), "<<< - >>> ParamType: ", param_type, " <<<");
        T tmp = p_in;
        return(tmp > value);
    };
};



void OnStart()
{

    test_obj            t_obj;
    const test_obj      ct_obj;
    test_obj*           p_obj           = new test_obj();
    const test_obj*     cp_obj          = new test_obj();
    test_obj            t_obj_arr[2];
    test_obj*           p_obj_arr[2]    = { new test_obj(), new test_obj() };
    const test_obj*     cp_obj_arr[2]   = { new test_obj(), new test_obj() };
    MqlRates            rate_arr[2];
    const MqlRates      c_rate_arr[2];
    MqlRates            rate;
    const MqlRates      c_rate;
    int                 i_arr[2];
    const int           ci_arr[2]       = { 11, 12 };
    const int           ci_v            = 5;
    int                 i_v             = 3;

    __test<test_obj>        t_c();
    __test<test_obj*>       t_p();
    __test<my_rates_close>  t_o();
    __test<int>             t_int();


    t_c.func(t_obj,                 __LINE__, typename(t_obj));             // __test<T>::func<U>(test_obj& t_obj)                  >>>T: class test_obj<<< -           >>>U: class test_obj<<< -           >>> ParamType: class test_obj <<<
    t_c.func(ct_obj,                __LINE__, typename(ct_obj));            // __test<T>::func<U>(const test_obj& ct_obj)           >>>T: class test_obj<<< -           >>>U: class test_obj const<<< -     >>> ParamType: class test_obj const <<<
    t_c.func(t_obj_arr,             __LINE__, typename(t_obj_arr));         // __test<T>::func<U>(const test_obj&[] t_obj_arr)      >>>T: class test_obj<<< -           >>>U: class test_obj<<< -           >>> ParamType: class test_obj [2] <<<
    t_c.func(p_obj,                 __LINE__, typename(p_obj));             // __test<T>::func<U>(test_obj* p_obj)                  >>>T: class test_obj<<< -           >>>U: class test_obj<<< -           >>> ParamType: class test_obj * <<<
    t_c.func(cp_obj,                __LINE__, typename(cp_obj));            // __test<T>::func<U>(const test_obj* cp_obj)           >>>T: class test_obj<<< -           >>>U: class test_obj const<<< -     >>> ParamType: class test_obj const * <<<
    t_c.func(p_obj_arr,             __LINE__, typename(p_obj_arr));         // __test<T>::func<U>(test_obj*&[] p_obj_arr)           >>>T: class test_obj<<< -           >>>U: class test_obj<<< -           >>> ParamType: class test_obj * [2] <<<


/*
    t_p.func(t_obj,         __LINE__);
    t_p.func(t_obj_arr,     __LINE__);
    t_p.func(p_obj,         __LINE__);
    t_p.func(p_obj_arr,     __LINE__);
*/

    t_o.func(rate_arr,              __LINE__, typename(rate_arr));          // __test<T>::func<U>(const MqlRates&[] rate_arr)       >>>T: struct my_rates_close<<< -    >>>U: struct MqlRates<<< -          >>> ParamType: struct MqlRates [2] <<<
    t_o.func(c_rate_arr,            __LINE__, typename(c_rate_arr));        // __test<T>::func<U>(const MqlRates&[] c_rate_arr)     >>>T: struct my_rates_close<<< -    >>>U: struct MqlRates<<< -          >>> ParamType: struct MqlRates const [2] <<<
    t_o.func(rate,                  __LINE__, typename(rate));              // __test<T>::func<U>(MqlRates& rate)                   >>>T: struct my_rates_close<<< -    >>>U: struct MqlRates<<< -          >>> ParamType: struct MqlRates <<<
    t_o.func(c_rate,                __LINE__, typename(c_rate));            // __test<T>::func<U>(const MqlRates& c_rate)           >>>T: struct my_rates_close<<< -    >>>U: struct MqlRates const<<< -    >>> ParamType: struct MqlRates const <<<


    t_int.func(3,                   __LINE__, typename(3));                 // __test<T>::func<U>(int 3)                >>>T: int<<< -  >>>U: int<<< -          >>> ParamType: int <<<
    t_int.func<const int>(i_v,      __LINE__, typename(i_v));               // __test<T>::func<U>(const int i_v)        >>>T: int<<< -  >>>U: int const<<< -    >>> ParamType: int <<<
    t_int.func<int>(ci_v,           __LINE__, typename(ci_v));              // __test<T>::func<U>(int ci_v)             >>>T: int<<< -  >>>U: int<<< -          >>> ParamType: int <<<
    t_int.func(i_arr,               __LINE__, typename(i_arr));             // __test<T>::func<U>(const int&[] i_arr)   >>>T: int<<< -  >>>U: int<<< -          >>> ParamType: int [2] <<<
    t_int.func(ci_arr,              __LINE__, typename(i_arr));             // __test<T>::func<U>(const int&[], ci_arr) >>>T: int<<< -  >>>U: int<<< -          >>> ParamType: int [2] <<<



    delete(p_obj);
    delete(cp_obj);
    delete(p_obj_arr[0]);
    delete(p_obj_arr[1]);
    delete(cp_obj_arr[0]);
    delete(cp_obj_arr[1]);

}


/*
LINE:81 Called from line: 122 - const bool __test<test_obj>::func<test_obj>(test_obj&,const int,const string) >>>T: class test_obj<<< - >>>U: class test_obj<<< - >>> ParamType: class test_obj <<<
LINE:81 Called from line: 123 - const bool __test<test_obj>::func<const test_obj>(const test_obj&,const int,const string) >>>T: class test_obj<<< - >>>U: class test_obj const<<< - >>> ParamType: class test_obj const <<<
LINE:73 Called from line: 124 - const bool __test<test_obj>::func<test_obj>(const test_obj&[],const int,const string) >>>T: class test_obj<<< - >>>U: class test_obj<<< - >>> ParamType: class test_obj [2] <<<
LINE:57 Called from line: 125 - const bool __test<test_obj>::func<test_obj>(test_obj*,const int,const string) >>>T: class test_obj<<< - >>>U: class test_obj<<< - >>> ParamType: class test_obj * <<<
LINE:57 Called from line: 126 - const bool __test<test_obj>::func<const test_obj>(const test_obj*,const int,const string) >>>T: class test_obj<<< - >>>U: class test_obj const<<< - >>> ParamType: class test_obj const * <<<
LINE:65 Called from line: 127 - const bool __test<test_obj>::func<test_obj>(test_obj*&[],const int,const string) >>>T: class test_obj<<< - >>>U: class test_obj<<< - >>> ParamType: class test_obj * [2] <<<

LINE:73 Called from line: 137 - const bool __test<my_rates_close>::func<MqlRates>(const MqlRates&[],const int,const string) >>>T: struct my_rates_close<<< - >>>U: struct MqlRates<<< - >>> ParamType: struct MqlRates [2] <<<
LINE:73 Called from line: 138 - const bool __test<my_rates_close>::func<MqlRates>(const MqlRates&[],const int,const string) >>>T: struct my_rates_close<<< - >>>U: struct MqlRates<<< - >>> ParamType: struct MqlRates const [2] <<<
LINE:81 Called from line: 139 - const bool __test<my_rates_close>::func<MqlRates>(MqlRates&,const int,const string) >>>T: struct my_rates_close<<< - >>>U: struct MqlRates<<< - >>> ParamType: struct MqlRates <<<
LINE:81 Called from line: 140 - const bool __test<my_rates_close>::func<const MqlRates>(const MqlRates&,const int,const string) >>>T: struct my_rates_close<<< - >>>U: struct MqlRates const<<< - >>> ParamType: struct MqlRates const <<<

LINE:89 Called from line: 143 - const bool __test<int>::func<int>(int,const int,const string) >>>T: int<<< - >>>U: int<<< - >>> ParamType: int <<<
LINE:89 Called from line: 144 - const bool __test<int>::func<const int>(const int,const int,const string) >>>T: int<<< - >>>U: int const<<< - >>> ParamType: int <<<
LINE:89 Called from line: 145 - const bool __test<int>::func<int>(int,const int,const string) >>>T: int<<< - >>>U: int<<< - >>> ParamType: int <<<
LINE:73 Called from line: 146 - const bool __test<int>::func<int>(const int&[],const int,const string) >>>T: int<<< - >>>U: int<<< - >>> ParamType: int [2] <<<
LINE:73 Called from line: 147 - const bool __test<int>::func<int>(const int&[],const int,const string) >>>T: int<<< - >>>U: int<<< - >>> ParamType: int [2] <<<

*/


For some reason, the keyword "const" gets occasionally dropped. But why? - Isnt this buggy behaviour?

I mean an r-value, like passing in a 3 into a function should resolve to a "const" value, shouldnt it... - But typename(3) will give only "int".

Also when passing in an int, the template "const int" gets expanded, and for the const int parameter, the "int" template gets expanded... - What is the sense behind this?

 
Dominik Christian Egert #:

I tried to understand how this is processed by the compiler and here is what I have found:


For some reason, the keyword "const" gets occasionally dropped. But why? - Isnt this buggy behaviour?

I don't see a const keyword being dropped, where ?

I mean an r-value, like passing in a 3 into a function should resolve to a "const" value, shouldnt it... - But typename(3) will give only "int".

Why ? Your template doesn't include a "const" why the compiler would add it ? Anyway it doesn't make a difference, only the "by value" template overload matches.

You would need to add the const in your (by reference) template, in theory, except it's not working in MQL (limitation not bug).

Also when passing in an int, the template "const int" gets expanded, and for the const int parameter, the "int" template gets expanded... - What is the sense behind this?

For sure, you called it explicitly !? An it's always the same template overload which is used because the compiler doesn't have a way to chose between by value or by reference, it always pick the by value one.

However, about your original question "why is it only "const int" that's not working? ". You are right, it's not quite clear why it's only with "const int" it gives an ambiguous call. I checked with C++ and it gives an error in the 3 cases.I don't know if it's by design from MQ developers or a bug. I will ask some explanation.