шаблоны template<typename T>

 

Здравствуйте, господа - товарищи!

Откопал где-то на бескрайних и адаптировал под свои нужды работу с CArrayObj при помощи шаблонов

Получилось неплохо


#define SORT_ASCENDING  1
#define SORT_DESCENDING 2
#include <Arrays\ArrayObj.mqh>

class CPositionAgent;
template<typename T>
class CPositionCollection : public CArrayObj
{
public:

//CPositionAgent  *operator[](const int inIndex) const { return (CPositionAgent*)At(inIndex);}
   T  *operator[](const int inIndex) const { return (T*)At(inIndex);}
};

class CPositionAgent : public CObject
{
public:

   ulong             meTicket;
   void CPositionAgent::CPositionAgent(ulong inTicket){this.meTicket=inTicket;return;}
   int CPositionAgent::Compare(const CObject *node,const int mode=0)const override
   {
   CPositionAgent *inNode = (CPositionAgent*)node;
   if( this.meTicket == inNode.meTicket ) 
      {return(0);
      }
   if( this.meTicket > inNode.meTicket )
     {
      return(1);
     }
   else
     {
      return(-1);
     }
   }
};

void OnStart()
{
 CPositionCollection<CPositionAgent> lCollOfPosAgents;
 //CPositionCollection lCollOfPosAgents;
   
   lCollOfPosAgents.Add(new CPositionAgent(1));
   lCollOfPosAgents.Add(new CPositionAgent(3));
   lCollOfPosAgents.Add(new CPositionAgent(2));
   lCollOfPosAgents.Add(new CPositionAgent(4));
   
   lCollOfPosAgents.Sort(SORT_DESCENDING);
   for(int i=0;i<lCollOfPosAgents.Total();i++)
   {
      Print(lCollOfPosAgents[i].meTicket);
   }
}


Но хочу спросить у тех, кто уже хорошо в этом разобрался. Почему недостаточно просто перегрузить оператор, а требуется выносить определение шаблона за класс и при создании экземпляра класса-коллекции, конкретизировать шаблон?

Иначе говоря, почему предыдущий код с правками, приведенными ниже, неверен?


#define SORT_ASCENDING  1
#define SORT_DESCENDING 2
#include <Arrays\ArrayObj.mqh>

class CPositionAgent;

//template<typename T>
class CPositionCollection : public CArrayObj
{
public:
template<typename T>
//CPositionAgent  *operator[](const int inIndex) const { return (CPositionAgent*)At(inIndex);}
   T  *operator[](const int inIndex) const { return (T*)At(inIndex);}
};

class CPositionAgent : public CObject
{
public:

   ulong             meTicket;
   void CPositionAgent::CPositionAgent(ulong inTicket){this.meTicket=inTicket;return;}
   int CPositionAgent::Compare(const CObject *node,const int mode=0)const override
   {
   CPositionAgent *inNode = (CPositionAgent*)node;
   if( this.meTicket == inNode.meTicket ) 
      {return(0);
      }
   if( this.meTicket > inNode.meTicket )
     {
      return(1);
     }
   else
     {
      return(-1);
     }
   }
};

void OnStart()
{
 //CPositionCollection<CPositionAgent> lCollOfPosAgents;
 CPositionCollection lCollOfPosAgents;
   
   lCollOfPosAgents.Add(new CPositionAgent(1));
   lCollOfPosAgents.Add(new CPositionAgent(3));
   lCollOfPosAgents.Add(new CPositionAgent(2));
   lCollOfPosAgents.Add(new CPositionAgent(4));
   
   lCollOfPosAgents.Sort(SORT_DESCENDING);
   for(int i=0;i<lCollOfPosAgents.Total();i++)
   {
      Print(lCollOfPosAgents[i].meTicket);
   }
}
 

В первом варианте более строгий код, где создается всего один оператор.

Во втором варианте - все просто криво)))) . Откуда создаваемому оператору по шаблону - возможно узнать в чего ему надо превратиться...чтобы... в общем чего то вернуть )))

Такие дела


Если чуть серьезнее. 

То шаблонные функции надо использоваться на получение шаблонного аргумента, а возврат уже сопутствующий. Т.к. при шаблоне функции будет создаваться именно эта функция автоматически по запросу... И не надо ничего объявлять. В справке есть классный пример с ArrayResize


Если хотим сделать только на возврат то надо выносить - иначе просто никак


И это фундаментально разные вещи..... 

В общем запутался даже с чего проще объяснить.... думаю проще начать со справки.  

Шаблонная функция -  автоматически досоздается по необходимости при компиляции в (где прописана). А шаблон класса - обязательно объявляться каким типом должен быть при создании

 
Alexandr Andreev:

В первом варианте более строгий код, где создается всего один оператор.

Во втором варианте - все просто криво)))) . Откуда создаваемому оператору по шаблону - возможно узнать в чего ему надо превратиться...чтобы... в общем чего то вернуть )))

Такие дела


Если чуть серьезнее. 

То шаблонные функции надо использоваться на получение шаблонного аргумента, а возврат уже сопутствующий. Т.к. при шаблоне функции будет создаваться именно эта функция автоматически по запросу... И не надо ничего объявлять. В справке есть классный пример с ArrayResize


Если хотим сделать только на возврат то надо выносить - иначе просто никак


И это фундаментально разные вещи..... 

В общем запутался даже с чего проще объяснить.... думаю проще начать со справки.  

Шаблонная функция -  автоматически досоздается по необходимости при компиляции в (где прописана). А шаблон класса - обязательно объявляться каким типом должен быть при создании

в каждой шутке есть доля правды )

я так это понял

template<typename T>
class CPositionCollection : public CArrayObj
// и вслед
CPositionCollection<CPositionAgent> lCollOfPosAgents;

как раз и укажут компилятору, что нужно вернуть здесь

return (T*)At(inIndex);

все логично. Спасибо!

 
Alexandr Andreev:

В первом варианте более строгий код, где создается всего один оператор.

Во втором варианте - все просто криво)))) . Откуда создаваемому оператору по шаблону - возможно узнать в чего ему надо превратиться...чтобы... в общем чего то вернуть )))

Такие дела

...

еще вопрос )

Как вынести код метода bool CPositionCollection::has(T *inPosAgent)

за пределы тела класса?

#define SORT_ASCENDING  1
#define SORT_DESCENDING 2
#include <Arrays\ArrayObj.mqh>

class CPositionAgent;
template<typename T>
class CPositionCollection : public CArrayObj
{
public:
   T  *operator[](const int inIndex) const { return (T*)At(inIndex);}
   bool CPositionCollection::has(T *inPosAgent)
      {
         for(int i=0;i<this.Total();i++)
         {
            if(inPosAgent.Compare(this[i]))
               {
                  return(true);
               }
         }
         return(false);
      }
};

 

class CPositionAgent : public CObject
{
public:

   ulong             meTicket;
   void CPositionAgent::CPositionAgent(ulong inTicket){this.meTicket=inTicket;return;}
   int CPositionAgent::Compare(const CObject *node,const int mode=0)const override
   {
   CPositionAgent *inNode = (CPositionAgent*)node;
   if( this.meTicket == inNode.meTicket ) 
      {return(0);
      }
   if( this.meTicket > inNode.meTicket )
     {
      return(1);
     }
   else
     {
      return(-1);
     }
   }
};

void OnStart()
{
 CPositionCollection<CPositionAgent> lCollOfPosAgents;
 //CPositionCollection lCollOfPosAgents;
   
   lCollOfPosAgents.Add(new CPositionAgent(1));
   lCollOfPosAgents.Add(new CPositionAgent(3));
   lCollOfPosAgents.Add(new CPositionAgent(2));
   lCollOfPosAgents.Add(new CPositionAgent(4));
   
   lCollOfPosAgents.Sort(SORT_DESCENDING);
   for(int i=0;i<lCollOfPosAgents.Total();i++)
   {
      Print(lCollOfPosAgents[i].meTicket);
   }
}
 
Nikolai Karetnikov:

еще вопрос )

Как вынести код метода bool CPositionCollection::has(T *inPosAgent)

за пределы тела класса?

template<typename T>
class CPositionCollection : public CArrayObj
{
public:
   T  *operator[](const int inIndex) const { return (T*)At(inIndex);}
   bool has(T *inPosAgent);
};

template<typename T>
 bool CPositionCollection::has(T *inPosAgent)
      {
         for(int i=0;i<this.Total();i++) if(inPosAgent.Compare(this[i])) return(true);
         return(false);
      }
 
 
Alexandr Andreev:
template<typename T>

Ставим перед описанием функции т.к. она принадлежит шаблонному классу, не зависимо от наличия входных аргументов

 
Alexandr Andreev:

Ставим перед описанием функции т.к. она принадлежит шаблонному классу, не зависимо от наличия входных аргументов

Работает. Спасибо! )