Pergunta datilografada

 

Caros programadores, há muito tempo eu tenho me intrigado com uma pergunta. É possível, de alguma forma, contornar e fazer uma digitação implícita do valor de retorno da função? Para que um método de uma classe devolva um valor de um tipo diferente, se a chamada dos métodos for externamente idêntica.

void OnStart()
 {
  CParameter p1 = Ask, p2 = Bid, p3 = TimeCurrent(), p4 = TimeLocal();
  
  // Перегруженный в CParameter оператор ~ возвращает преобразованное в строку значение известного объекту типа
  
  printf( "p1=%s, p2=%s, p3=%s, p4=%s", ~p1, ~p2, ~p3, ~p4 );
  
  // А можно ли исхитриться и сделать вот так (допустим это будет перегруженный тем или иным образом оператор !, возвращающий
  //   значение нужного типа в зависимости от type. 
  //
  // double ask = !p1, bid = !p2;
  // datetime current = !p3, local = !p4;  
 }  

Esta é a classe em si, você não precisa olhar para ela, se a pergunta for clara.

enum TYPE{ NUMBER, PRICE, TIME };

class CParameter
 {
public:
  template<typename T> void operator= ( T par )
   {
    if( typename( T ) == "double" )
     {
      data = int( double( par ) * 100000 );
      type = PRICE;
     }
    else
     {
      if( typename( T ) == "datetime" )
       {
        data = int( uint( par ) );
        type = TIME;
       }
      else
       {
        data = int( par );
        type = NUMBER;
       }
     }
   }
   
  double to_price()
   {
    switch(type)
     {
      case PRICE: return double( data ) / 100000;
      case TIME:  return MathArcsin(2.0);
      default:    return double( data );
     }
   }

  datetime to_time()
   {
    switch(type)
     {
      case TIME:  return datetime( data );
      default:    return 0;
     }
   }

  int to_number()
   {
    switch(type)
     {
      case PRICE: return int( double( data ) / 100000 );
      case TIME:  return 0;
      default:    return data;
     }
   }
   
  string to_string()
   {
    switch(type)
     {
      case PRICE: return DoubleToString( to_price(), 5 );
      case TIME:  return TimeToString( to_time(), TIME_DATE|TIME_SECONDS );
      default:    return IntegerToString( data );
     }
   }
   
  string operator~ ()
   {
    return to_string();
   }
   
private:
  int data;
  TYPE type;
 };
 

Você também pode se livrar do swich ao atribuir e aproveitar a capacidade de sobrecarga:

   void operator=(double par){
      data = int(double(par)*100000 );
      type = PRICE;
   }
   void operator=(datetime par){
      data=int(uint(par));
      type=TIME;
   }
   void operator=(int par){   
      data = int(par);
      type = NUMBER;
   }

Então, se o valor de retorno deve ser usado para uma ação aritmética (para que haja algo a ser referenciado), é mais ou menos o mesmo:

   string operator+(string par){
      return to_string()+par;
   }
   
   double operator+(double par){
      return to_price()+par;
   }   
   
   double operator+(int par){
      return to_number()+par;
   }  
Print(p1+1);
Print(p1+1.0);
Print(p1+"1");

---

Se por mim mesmo, eu faria funções sobrecarregadas com retorno via parâmetro por referência.

   void r(double & v){
      v=to_price();
   }
   void r(int & v){
      v=to_number();
   }   
   void r(string & v){
      v=to_string();
   }   
 
Dmitry Fedoseev:

Você também pode se livrar do swich ao atribuir e aproveitar a capacidade de sobrecarga:

Então, se o valor de retorno será usado para uma ação aritmética (para que haja algo a ser procurado), é mais ou menos o mesmo:

Com a sobrecarga explícita e ações aritméticas, é claro como é. Sim, sobrecarregado = claramente melhor neste caso, você está certo, eu estava apenas construindo rapidamente um exemplo para uma pergunta e não pensei realmente sobre isso (embora não só int, mas também char, uchar, short, ushort, uint, bool e cor, então nem tudo é simples )))))))).

Dmitry Fedoseev:

Se eu fizesse funções sobrecarregadas com retorno de parâmetro por referência.


A questão aqui é que o tipo de valor de retornodo método sobrecarregado depende do conteúdo do objeto.

Por exemplo, temos um conjunto de vários tipos (não citarei exemplos, já que existem muitos livros). E, claro, qualquer matriz deve ter a operação [] de indexação que retorna o valor de uma variável com um índice apropriado.

Mas as variáveis têm tipos diferentes. Pode haver data ou string ou algum outro tipo definido pelo usuário sob este índice. E, idealmente, gostaria que o tipo de valor de retorno saísse automaticamente o tipo apropriado ao indexar [], sem ter que parametrizá-lo explicitamente. Eu costumava resolver este "problema" desta maneira: var[(char)1], var[(short)1], var[(uint)1] etc., mas estas muletas não funcionam.

 
void OnStart()
 {
  CParameter<double> p1 = Ask;
  CParameter<double> p2 = Bid;
  CParameter<datetime> p3 = TimeCurrent();
  CParameter<datetime> p4 = TimeLocal();
  
  // Перегруженный в CParameter оператор ~ возвращает преобразованное в строку значение известного объекту типа
  
  printf( "p1=%s, p2=%s, p3=%s, p4=%s", ~p1, ~p2, ~p3, ~p4 );
  
  // А можно ли исхитриться и сделать вот так (допустим это будет перегруженный тем или иным образом оператор !, возвращающий
  //   значение нужного типа в зависимости от type. 
  //
   double ask = !p1, bid = !p2;
   datetime current = !p3, local = !p4;  
 }  
template <typename T>
class CParameter
 {
public: 
  void operator =( const T Value )
  {
    this.data = Value;
  }

  string operator~( void) const
   {
    return((string)this.data);
   }
   
  T operator !( void ) const
  {
    return(this.data);
  }  
   
private:
  T data;
 };
 
fxsaber:

Neste caso, não é possível atribuir p1 a p4 (com mudança de tipo), e isto deve ser possível, em princípio.

Ou no caso de array - objetos de diferentes tipos com um tipo base, mas o próprio objeto array tem um método, cujo tipo de retorno depende do tipo de objeto com índice correspondente
 
uma pergunta semelhante: por que é que ao sobrecarregar um método (na assinatura do método sobrecarregado) o tipo de retorno não aparece, apenas os tipos de parâmetros aparecem. ou seja, você não pode definir dois métodos idênticos com tipos de retorno diferentes. por que esta restrição é feita? qual é o objetivo, por que você não pode sobrecarregar um método por tipo de retorno com parâmetros idênticos?
 
Ilya Malev:

Neste caso, não é possível atribuir p1 a p4 (com uma mudança de tipo), o que, em princípio, deveria ser possível.

Ou no caso de array - objetos de diferentes tipos com um tipo base, mas o próprio objeto array tem um método, cujo tipo de retorno depende do tipo de objeto com índice correspondente

https://www.mql5.com/ru/docs/constants/structures/mqlparam

Документация по MQL5: Константы, перечисления и структуры / Структуры данных / Структура входных параметров индикатора
Документация по MQL5: Константы, перечисления и структуры / Структуры данных / Структура входных параметров индикатора
  • www.mql5.com
каждого элемента этого массива указывает тип данных, передаваемых данным элементом. Сами значения параметров индикатора необходимо предварительно поместить в соответствующие поля каждого элемента (в...
 

Sim, para transmitir 32 bytes quando em 90% dos casos 4 é suficiente... De qualquer forma, esse não é o objetivo deste tópico, estou interessado no propósito - pode ser alguém encontrado com uma solução mais ou menos graciosa na situação descrita


p.s. Além disso, a questão não é armazenar diferentes tipos de dados em um objeto/estrutura, de forma alguma

 
Ilya Malev:
uma pergunta semelhante: por que quando um método é sobrecarregado (na assinatura do método sobrecarregado) o tipo de retorno não aparece, apenas os tipos de parâmetros aparecem. ou seja, não é possível definir dois métodos idênticos com tipos de retorno diferentes. por que esta restrição é feita? qual é o objetivo, por que não é possível sobrecarregar um método por tipo de retorno com parâmetros idênticos

O método não pode decidir o tipo de retorno.

 
fxsaber:

Um método não pode decidir que tipo de retorno.

Bem, em outras palavras, você repetiu o que eu escrevi. A questão não era se ela pode ou não pode, mas por que não pode e como trabalhar elegantemente em torno dela

 
Ilya Malev:

Bem, em outras palavras, você repetiu o que eu escrevi. A questão não era se ela pode ou não pode, mas por que não pode e como contorná-la graciosamente.

O controle de tipo é perdido. Consulte os recursos do C++ para obter respostas a estas perguntas. Acho que são perguntados com bastante frequência.

Razão: