Cuestión de mecanografía

 

Estimados programadores, llevo mucho tiempo dándole vueltas a una pregunta. ¿Es posible ingeniárselas de alguna manera y hacer una tipificación implícita del valor de retorno de la función? Para que un método de una clase devuelva un valor de un tipo diferente, si las llamadas a los métodos son externamente idénticas.

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 es la clase en sí, no hay que mirarla, si la pregunta es 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;
 };
 

También puede deshacerse de swich al asignar y aprovechar las capacidades 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;
   }

Luego, si el valor de retorno se va a utilizar para una acción aritmética (para que haya algo a lo que hacer referencia), es más o menos lo mismo:

   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");

---

Si por mí fuera, haría funciones sobrecargadas con retorno vía parámetro por referencia.

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

También puede deshacerse de swich al asignar y aprovechar las capacidades de sobrecarga:

Entonces, si el valor de retorno se utilizará para una acción aritmética (para que haya algo que buscar), es más o menos lo mismo:

Con la sobrecarga explícita y las acciones aritméticas, está claro como es. Sí, sobrecargado = claramente mejor en este caso, tienes razón, yo sólo estaba construyendo rápidamente un ejemplo para una pregunta y no realmente pensado en ello (aunque hay número no sólo int, sino también char, uchar, short, ushort, uint, bool y color, por lo que no todo es simple )))))))).

Dmitry Fedoseev:

Si hiciera funciones sobrecargadas con retorno de parámetros por referencia.


El problema aquí es que el tipo del valor de retorno delmétodo sobrecargado depende del contenido del objeto.

Por ejemplo, tenemos una matriz de varios tipos (no citaré ejemplos, ya que hay muchos libros). Y por supuesto, cualquier array debe tener la operación de indexación [] que devuelve el valor de una variable con un índice apropiado.

Pero las variables tienen diferentes tipos. Puede ser datetime o string o incluso algún tipo definido por el usuario bajo este índice. Y lo ideal sería que el tipo de valor de retorno produjera automáticamente el tipo apropiado al indexar [], sin tener que parametrizarlo explícitamente. Solía resolver este "problema" de esta manera: var[(char)1], var[(short)1], var[(uint)1] etc., pero estas muletas no funcionan.

 
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:

En este caso, no se puede asignar p1 a p4 (con cambio de tipo), y esto debería ser posible en principio.

O en el caso del array - objetos de diferentes tipos con un tipo base, pero el propio objeto del array tiene un método, cuyo tipo de retorno depende del tipo de objeto con el índice correspondiente
 
una pregunta similar: ¿por qué cuando se sobrecarga un método (en la firma del método sobrecargado) no aparece el tipo de retorno, sólo aparecen los tipos de los parámetros. es decir, no se pueden definir dos métodos idénticos con diferentes tipos de retorno. por qué esta restricción? ¿qué sentido tiene, por qué no se puede sobrecargar un método por el tipo de retorno de parámetros idénticos?
 
Ilya Malev:

En este caso no se puede asignar p1 a p4 (con un cambio de tipo), lo que en principio debería ser posible.

O en el caso del array - objetos de diferentes tipos con un tipo base, pero el propio objeto del array tiene un método, cuyo tipo de retorno depende del tipo de objeto con el índice correspondiente

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

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

Sí, para transmitir 32 bytes cuando en el 90% de los casos basta con 4... De todos modos, ese no es el punto de este hilo, estoy interesado con el propósito - puede ser que alguien encontró una solución más o menos elegante en la situación descrita


p.s. Además, la pregunta no es sobre el almacenamiento de diferentes tipos de datos en un objeto/estructura, en absoluto

 
Ilya Malev:
una pregunta similar: por qué al sobrecargar un método (en la firma del método sobrecargado) no aparece el tipo de retorno, sólo aparecen los tipos de parámetros. es decir, no se pueden definir dos métodos idénticos con diferentes tipos de retorno. por qué se hace esta restricción? cuál es el sentido, por qué no se puede sobrecargar un método por tipo de retorno con parámetros idénticos

El método no puede decidir qué tipo devolver.

 
fxsaber:

Un método no puede decidir qué tipo devolver.

Bueno, en otras palabras, has repetido lo que yo escribí. La cuestión no era si se puede o no, sino por qué no se puede y cómo evitarlo con elegancia

 
Ilya Malev:

En otras palabras, has repetido lo que yo escribí. La cuestión no era si puede o no puede, sino por qué no puede y cómo sortearlo con elegancia.

Se pierde el control del tipo. Busque las respuestas a estas preguntas en los recursos de C++. Creo que se preguntan bastante a menudo.