Writing generic code in MQL for Objects [solved] - page 2

 
Dominik Christian Egert:

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

...

By the way, what are you trying to achieve exactly ?

 
Alain Verleyen #:
I don't see a const keyword being dropped, where ?

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).

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.

Well, to my understanding, it gets dropped. Here is the comparison, I was making to conclude this:

    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 <<<

Versus:

t_int.func<int>(ci_v,           __LINE__, typename(ci_v));              // __test<T>::func<U>(int ci_v)             >>>T: int<<< -  >>>U: int<<< -          >>> ParamType: int <<<


Yes, I know, I called it explicit, thats on purpose. - Else it wont compile.

But the main question is, why is the const not passed forward to the function template? - Shouldnt it be? - I know, its a copy inside the function and any change would not reflect to the passed parameter.

    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 <<<


But why, if this template is available, expanded with "int", not "const int", is it required to have a "int" signature to take in the const declared int variable as parameter?

t_int.func<int>(ci_v,           __LINE__, typename(ci_v));              // __test<T>::func<U>(int ci_v)             >>>T: int<<< -  >>>U: int<<< -          >>> ParamType: int <<<


C/C++ behaves totally different in this regard, I know about that. - But in C/C++, I would know how to design a functions signature to take in all required inputs, which leads me to your next post/question, I will answer there.

 
Alain Verleyen #:

By the way, what are you trying to achieve exactly ?

My goal is to have a function signature/function-call, which is able to take in all types, except for enum and bool.

So what I would like to have is a function that can be called with

- pointer

- class-object

- struct-object

- literals/primitives (iE int, datetime, double ...)

- r-values of primitive-types. (iE D'2020.01.01', 0x01, 4, 1.002 and so on)

so that I have one function name, like __func(), and I can pass in any of the above mentioned values.

EDIT:

Also arrays as applicable, of course.

 
Dominik Christian Egert #:

My goal is to have a function signature/function-call, which is able to take in all types, except for enum and bool.

So what I would like to have is a function that can be called with

- pointer

- class-object

- struct-object

- literals/primitives (iE int, datetime, double ...)

- r-values of primitive-types. (iE D'2020.01.01', 0x01, 4, 1.002 and so on)

so that I have one function name, like __func(), and I can pass in any of the above mentioned values.

EDIT:

Also arrays as applicable, of course.

It's impossible currently, too much mql limitations.

Well maybe there is a way, but it will need to be so complicated and hacked that it's not worth it in my opinion.

 
Alain Verleyen #:

It's impossible currently, too much mql limitations.

Well maybe there is a way, but it will need to be so complicated and hacked that it's not worth it in my opinion.

Yes, I know it's impossible. But I think a bug is the issue for it being impossible.

Somewhere is a twist or an inconsistency in how the compiler handles "const int" and "int".

As I showed, and I'll try to break it down even more, but for now, I need to have a "const int" signature to handle a "int" variable as input parameter...

Edit:

Currently I have all covered, except for const literals...

You are right, it takes some effort.
 
Alain Verleyen #:

It's impossible currently, too much mql limitations.

Well maybe there is a way, but it will need to be so complicated and hacked that it's not worth it in my opinion.

I would like to hear your opinion on this code:


struct my_rates_time : public MqlRates
{
    // Default constructor
    my_rates_time()                                         {};
    my_rates_time(  const datetime _time,
                    const double _open,
                    const double _high,
                    const double _low,
                    const double _close,
                    const long _tick_volume,
                    const int _spread,
                    const long _real_volume)                { };

    // Copy constructor
    my_rates_time(const MqlRates& obj)                      { this = obj; };

    // Operators
    const bool  operator> (const my_rates_time& obj) const  { return(time > obj.time); };

    void        operator= (const MqlRates& obj)             { 
                                                                time        = obj.time;
                                                                open        = obj.open; 
                                                                high        = obj.high;
                                                                low         = obj.low;
                                                                close       = obj.close;
                                                                tick_volume = obj.tick_volume;
                                                                spread      = obj.spread;
                                                                real_volume = obj.real_volume;
                                                            };
};

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)
    { Print("Copy C"); };

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


class test_derived : public test_obj
{
    public:
    test_derived()
    { };
    
    test_derived(const test_derived& p_in) :
        test_obj(p_in)
    { Print("Copy D"); };

    test_derived(const test_obj& p_in) :
        test_obj(p_in)
    { Print("Copy E"); };

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

template <typename TARGET_TYPE, typename SOURCE_TYPE>
void __func(TARGET_TYPE& p_out, const SOURCE_TYPE& p_in)
{ 
    p_out = p_in;
};

template <typename TARGET_TYPE, typename SOURCE_TYPE>
void __func(TARGET_TYPE& p_out, const SOURCE_TYPE* p_in)
{ 
    p_out = TARGET_TYPE(p_in);
};

template <typename TARGET_TYPE, typename SOURCE_TYPE>
void __func(TARGET_TYPE& p_out, const SOURCE_TYPE p_in)
{ 
    p_out = p_in;
};

void OnStart()
{
    test_obj        target_obj;
    test_obj*       target_ptr  = new test_obj();
    my_rates_time   target_struct;
    int             target_int;
    
        test_obj                    _obj();
        const test_obj              c_obj();
        test_obj*                   _ptr        = GetPointer(_obj);
        const test_obj*             c_ptr       = new test_obj();
        test_derived                _d_obj();
        const test_derived          c_d_obj();
        test_derived*               _d_ptr        = GetPointer(_d_obj);
        const test_derived*         c_d_ptr       = new test_derived();
        MqlRates                    _rates;
        const MqlRates              c_rates;
        my_rates_time               _struct;
        const my_rates_time         c_struct;
        int                         _int        = 5;
        const int                   c_int       = 8;


    __func(target_obj, _obj);
    __func(target_obj, c_obj);
    __func(target_obj, _ptr);
    __func(target_obj, c_ptr);

    __func(target_obj, _d_obj);
    __func(target_obj, c_d_obj);
    __func(target_obj, _d_ptr);
    __func(target_obj, c_d_ptr);


    __func(target_ptr, _obj);
    __func(target_ptr, c_obj);
    __func(target_ptr, _ptr);
    __func(target_ptr, c_ptr);

    __func(target_ptr, _d_obj);
    __func(target_ptr, c_d_obj);
    __func(target_ptr, _d_ptr);
    __func(target_ptr, c_d_ptr);


    __func(target_struct, _rates);
    __func(target_struct, c_rates);
    __func(target_struct, _struct);
    __func(target_struct, c_struct);


    __func(target_int, 7);                   // Resolves to the third template of __func()
    __func(target_int, _int);                // Resolves to the third template of __func() - I did expect this to resolve to the first template
    __func(target_int, (const int)c_int);    // Resolves to the third template of __func() - Does not compile without cast....

}

As you can see, I did a cast on the constant variable, so it is required to match the third template. - But, if I dont cast the variable, the compiler cannot select a matching template, and complains about ambiguous call. - But shouldnt this also be the case for the non-const call one line above??

Why does the compiler select the non-reference call for the non-const variable, instead of the reference-call. - And, why does the const variable not match as the non-const variable.


This is (I am quite confident now) obviously an inconsistent behaviour, especially, because it works for pointer, objcets and structs exactly as expected. - I make my claim, this is a bug in the compilers template matching algorithm.

What do you think?


EDIT:

And to proove my point further, if you change the first template like this, and change the call to the __func() as shown below, the compiler suddenly switches over to have issues with the non-const variable. The behaviour now is vice-versa between "int" and "const int".


template <typename TARGET_TYPE, typename SOURCE_TYPE>
void __func(TARGET_TYPE& p_out, SOURCE_TYPE& p_in)
{ 
    p_out = p_in;
};


...

    __func(target_int, 7);
    __func(target_int, (int)_int);
    __func(target_int, c_int);


If you remove the cast operation within the function call, the compiler will complain again. - And it is vice-versa with the const declarations. - The compilers matching for "const" and "non-const" is mixed up.

 
Dominik Christian Egert #:

I would like to hear your opinion on this code:

...

I don't have time currently (for some days), I will check when possible (don't hesitate to ask again in case I forget).

 
Dominik Christian Egert #:

I would like to hear your opinion on this code:

This is (I am quite confident now) obviously an inconsistent behaviour, especially, because it works for pointer, objcets and structs exactly as expected. - I make my claim, this is a bug in the compilers template matching algorithm.

What do you think?

I don't have time myself as well but I encountered these kind of problems in compiler matching template methods in template classes as well.

I didn't bother to point it out and isolate the problems like you do, because I think as long as we don't have interfaces in MQL5 all these templates are very limited as well.

 
Amir Yacoby #:

I don't have time myself as well but I encountered these kind of problems in compiler matching template methods in template classes as well.

I didn't bother to point it out and isolate the problems like you do, because I think as long as we don't have interfaces in MQL5 all these templates are very limited as well.

interesting.

So you would as well state, this is awkward behavior?

What kind of interfaces are you talking about? Marshalling? Because standard interfaces are available. What we don't have are lambdas. But that could be at least partially mimicked with templates and virtual functions, if templating were to work fully.

But, interfaces are available. Not template overloading and not virtual template member functions... but interfaces... :-)
 
Alain Verleyen #:

I don't have time currently (for some days), I will check when possible (don't hesitate to ask again in case I forget).

Thank you, I will come back to you again, in case you forget...
Reason: