Erreurs, bugs, questions - page 2639

 
Petros Shatakhtsyan:

Vous ne comprenez toujours pas de quoi il s'agit, vous ne lisez probablement pas mes messages avec attention. Mon appel s'adresse aux développeurs, pas à vous. Je n'ai pas besoin de tes conseils minables.

Calmez-vous et ne vous inquiétez pas tant.

Une fois de plus, je suis convaincu que les personnes ayant un faible développement cérébral ont généralement peu de compréhension de la civilité.

Vous ne comprenez même pas ce que vous disent des personnes plus compétentes, et vous êtes aussi grossier qu'un enfant de maternelle qui n'a même pas appris à écrire correctement.

 
Malheureusement, ou peut-être heureusement, je ne fais pas de développement direct,
Cependant, c'est le travail sur les projets qui vous permet d'évaluer les capacités de la langue et de découvrir ses défauts et ses bogues...

Auparavant, lors du travail sur les projets MQL, les informations sur les défauts (bugs) étaient fournies dans l'ordre de leur détection.
Nous avons maintenant décidé d'essayer une nouvelle approche - travailler jusqu'à un défaut bloquant et ensuite fournir des informations sur tous les défauts détectés.
 
#ifdef __cplusplus
   #include <iostream>
#endif 

#define  PRINT(x) ; Print(#x, ":", string(x))


template<typename T>
class main_wrapper{
public:
   T data;
};

template<typename T>
class external_wrapper{
public:
   T data;
};

template<typename T>
class A{
public:
   class internal_wrapper : public external_wrapper<T> {};
   
   main_wrapper<internal_wrapper> internal_wrapper_0;
   main_wrapper<external_wrapper<T>> external_wrapper_0;
   
   A(){
        main_wrapper<internal_wrapper> internal_wrapper_1;
        main_wrapper<external_wrapper<T>> external_wrapper_1;
   
        #ifdef __MQL5__
            PRINT(__FUNCSIG__);
            PRINT(typename(internal_wrapper_0.data.data));      // (Bug) int  int
            PRINT(typename(external_wrapper_0.data.data));      // (OK)  int  B*
            PRINT(typename(internal_wrapper_1.data.data));      // (Bug) int  int
            PRINT(typename(external_wrapper_1.data.data));      // (OK)  int  B*
        #endif
   }
};

class B{
   char data[10];
};

class C{
   char data[1000];
};


void OnStart()
{ 
   A<int> val_int;
   A<B*> val_ptr;
   
   printf("%d\n", sizeof(main_wrapper<A<B>::internal_wrapper>));  // (Bug) 36  //sizeof(main_wrapper<A<int>::internal_wrapper>) is used
   printf("%d\n", sizeof(main_wrapper<A<C>::internal_wrapper>));  // (Bug) 36  //sizeof(main_wrapper<A<int>::internal_wrapper>) is used
}

int main(){
   OnStart();
   return 1;
}
Très mauvais bug de MT5 (build 2316), bloquant tout développement ultérieur.
Vous créez plusieurs fois un objet enveloppé complexe avec le type interne "C", mais il s'avère être un type de données tout à fait différent, peut-être "B", "int", ce que vous voulez...

Il m'a fallu beaucoup de temps et d'efforts pour trouver et comprendre que le problème ne se situe pas dans le code mais dans le compilateur MQL. (C++ en ligne: https://onlinegdb.com/H1R1fR5ML)
Vraisemblablement, le problème se situe dans le travail du cache de la classe de modèle "main_wrapper" lors de la génération du code à la compilation lorsque la classe interne "internal_wrapper" de la classe de modèle "A" est passée en paramètre pour différents types de données (int, B*, B, C).
Le premier type de données est créé par la classe de modèle "main_wrapper<A<TEMPLATE_TYPE>::internal_wrapper>, ce type de données sera utilisé ultérieurement dans tous les objets du modèle.


Un autre bogue concernant la génération du code de la classe du modèle sera présenté ci-dessous.
 
class A{
public:
   class B{};
};

template<typename T>
class wrapper{
public:
   T data;
};

template<typename T>
class wrapped_B{
public:
   A::B data;
};
   
void OnStart()
{ 
   A::B a;                // OK
   wrapper<A::B> b0;      // 'B' - unexpected token, probably type is missing?  'data' - semicolon expected     
   
   wrapped_B<A::B> b2;    // OK
   
   class local_B : public A::B{};
   wrapper<local_B> b1;   // OK
}


int main(){
   OnStart();
   return 0;
}

Un autre bogue MT5 (build 2316) avec la génération de code de classe de modèle lors de l'utilisation de classe interne.
C++ en ligne: https://onlinegdb.com/HJkKXAqMU

 
template<typename T>
class type_wrapper{
    T data;
};

template<typename T>
class A{
   class type_wrapper : public :: type_wrapper<T>{}; // '::' - syntax error      
};

void OnStart()
{ 
   A<int> a;
}


int main(){
   OnStart();
   return 0;
}

Un autre défaut deMT5(build 2316) lié à laclasse interne est l'absence de possibilité de référencer explicitement l'espace de nom global.
C++ en ligne: https://onlinegdb.com/H14NF05G8

 
Sergey Dzyublik:
Un bogue très désagréable qui bloque la poursuite du développement.
Vous créez plusieurs fois un objet enveloppé complexe avec le type interne "C", mais il s'avère être un type de données tout à fait différent, peut-être "B", "int", ce que vous voulez...

Il m'a fallu beaucoup de temps et d'efforts pour trouver et comprendre que le problème ne se situe pas dans le code mais dans le compilateur MQL. (C++ en ligne: https://onlinegdb.com/H1R1fR5ML)
Vraisemblablement, le problème se situe dans le travail du cache de la classe de modèle "main_wrapper" lors de la génération du code à la compilation lorsque la classe interne "internal_wrapper" de la classe de modèle "A" est passée en paramètre pour différents types de données (int, B*, B, C).
Le premier type de données est créé par la classe de modèle "main_wrapper<A<TEMPLATE_TYPE>::internal_wrapper>, ce type de données sera utilisé ultérieurement dans tous les objets du modèle.


Un autre bogue concernant la génération du code de la classe du modèle sera présenté ci-dessous.
#ifdef __cplusplus
   #include <iostream>
#endif 

#define  PRINT(x) ; Print(#x, ":", string(x))


template<typename T>
class main_wrapper{
public:
   T data;
};

template<typename T>
class external_wrapper{
public:
   T data;
};

template<typename T>
class A{
public:
   template<typename T1>
   class internal_wrapper : public external_wrapper<T1> {};
   
   main_wrapper<internal_wrapper<T>> internal_wrapper_0;
   main_wrapper<external_wrapper<T>> external_wrapper_0;
   
   A(){
        main_wrapper<internal_wrapper<T>> internal_wrapper_1;
        main_wrapper<external_wrapper<T>> external_wrapper_1;
   
        #ifdef __MQL5__
            PRINT(__FUNCSIG__);
            PRINT(typename(internal_wrapper_0.data.data));      // (Bug) int  int
            PRINT(typename(external_wrapper_0.data.data));      // (OK)  int  B*
            PRINT(typename(internal_wrapper_1.data.data));      // (Bug) int  int
            PRINT(typename(external_wrapper_1.data.data));      // (OK)  int  B*
        #endif
   }
};

class B{
   char data[10];
};

class C{
   char data[1000];
};


void OnStart()
{ 
   A<int> val_int;
   A<B*> val_ptr;
   
   printf("%d\n", sizeof(main_wrapper<A<B>::internal_wrapper<B>>));  // (Bug) 36  //sizeof(main_wrapper<A<int>::internal_wrapper>) is used
   printf("%d\n", sizeof(main_wrapper<A<C>::internal_wrapper<C>>));  // (Bug) 36  //sizeof(main_wrapper<A<int>::internal_wrapper>) is used
}
Est-ce correct ?
 
Vladimir Simakov:
Est-ce la bonne façon de procéder ?

Merci, en effet l'introduction d'un paramètre de modèle fictif, dans le cas de l'exemple, permet de contourner le problème.
Cependant, en ce qui concerne le projet global, les choses sont un peu plus compliquées : laclasse interne a été utilisée comme une alternative à la fonctionnalité manquante typedef typename afin de simplifier à la fois le processus de développement et l'application de la classe conteneur finale.
Cela vaut peut-être la peine d'attendre une correction de la part des développeurs.
En dernier recours, il faudra faire glisser toutes les dépendances vers l'extérieur, en espérant ne plus réussir la compilation avec un comportement indéfini au moment de l'exécution.

 

Pour résumer la fonctionnalité de la classe interne,
nous pouvons clairement dire qu'il manque la fonctionnalité de déclaration typedef, du moins sa forme primitive, pour l'utiliser correctement...
Ainsi, au lieu d'un code C++ assez compact et clair :

template <class _Tp, class _Allocator>
class vector
    : private __vector_base<_Tp, _Allocator>
{
private:
    typedef __vector_base<_Tp, _Allocator>           __base;
public:
    typedef vector                                   __self;
    typedef _Tp                                      value_type;
    typedef _Allocator                               allocator_type;
    typedef typename __base::__alloc_traits          __alloc_traits;
    typedef typename __base::reference               reference;
    typedef typename __base::const_reference         const_reference;
    typedef typename __base::size_type               size_type;
..............................


Nous devons construire une barrière avec #define et l'héritage par la classe interne :

template<typename _Tp, typename _Allocator>
class __vector_base{
public:
   class allocator_type    : public _Allocator{}; 
   
protected:
   #define  value_type          _Tp
   #define  size_type           DEFAULT_SIZE_TYPE
   #define  difference_type     size_type
   
   struct pointer          : public allocator_type::pointer{};
   struct iterator         : public allocator_type::pointer{};
............................

   #undef  value_type
   #undef  size_type
   #undef  difference_type
};


Et il y a beaucoup plus de problèmes ici qu'il n'y paraît à première vue.
Des problèmes surviennent lors de l'utilisation de #define comme déclaration typedef :

- il n'y a aucun moyen de transmettre le type de données utilisé en dehors de la classe (il n'y a aucun moyen de transmettre des types de données simples) ;
- il est nécessaire de contrôler constamment la portée de #define avec la paire #undef correspondante

Problèmes lors de l'utilisation d'une classe interne comme déclaration typedef :
- il est possible de passer le type de données de la classe/structure utilisé en dehors de la classe (les types de données simples ne peuvent pas être passés du tout) ;
- l'héritage fait perdre tous les constructeurs, ils doivent être réécrits manuellement en utilisant les signatures de la classe de base ;
- si la classe dans laquelle la déclaration typedef est utilisée a une classe de base, alors par le chevauchement des espaces de noms il n'y a aucun moyen d'utiliser le même nom que la déclaration typedef ;
- les classes héritent des classes, les structures des structures, ceci doit être constamment contrôlé ;
 
En raison de l'introduction des opérateurs d'affectation par défaut, il est apparu nécessaire d'interdire l'exécution d'affectations aléatoires pour la classe de base.
Les développeurs ont ajouté "operator= delete" à cet effet.
Cependant, il ne semble pas logique de rompre le lien suppression/par défaut, car tout doit être réécrit manuellement.
Peut-être que je fais quelque chose de mal ?

class Base{
    char base_data[100];
};

template<typename T>
class A : public Base{
   int data_1;
   int data_2;
   int data_3;
   int data_4;
   int data_5;
   int data_6;
   int data_7;
   int data_8;
   int data_9;
   
   char arr_1[];
   char arr_2[];
public:    
   // MQL
   A* operator=(A &obj){
      data_1 = obj.data_1; 
      data_2 = obj.data_2; 
      data_3 = obj.data_3; 
      data_4 = obj.data_4; 
      data_5 = obj.data_5; 
      data_6 = obj.data_6; 
      data_7 = obj.data_7; 
      data_8 = obj.data_8; 
      data_9 = obj.data_9; 
      
      ArrayCopy(arr_1, obj.arr_1);
      ArrayCopy(arr_2, obj.arr_2); 
      
      (Base)this = obj;
      return &this;
   };
   
   // C++
   // A& operator=(A &) = default;
    
   template<typename TT>
   A* operator=(A<TT> &) = delete;
};

void OnStart()
{ 
   A<int> a;
   A<int> b;
   
   A<double> c;
   
   a = b;      
   //a = c;       
}
 

Il y a une erreur dans la documentation sur le site web:

Calculs basés sur les séries chronologiques de la période actuelle

int  OnCalculate(
   const int        rates_total,       // размер входных таймсерий
   const int        prev_calculated,   // количество обработанных баров на предыдущем вызове
   const datetime&  time{},            // массив Time
   const double&    open[],            // массив Open
   const double&    high[],            // массив High
   const double&    low[],             // массив Low
   const double&    close[],           // массив Close
   const long&      tick_volume[],     // массив Tick Volume
   const long&      volume[],          // массив Real Volume
   const int&       spread[]           // массив Spread
   );

Des parenthèses formées au lieu de parenthèses carrées.