タイピングに関する質問

 

プログラマーの皆さん、私は長い間、ある疑問に頭を悩ませていました。関数の戻り値を暗黙のうちに型付けすることは可能でしょうか?そのため、あるクラスのメソッドを 呼び出すと、外部的に同一のメソッドであれば、異なる型の値を返します。

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

これは授業そのものであり、質問が明確であれば見る必要はない。

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

また、アサインする際にswichを取り除くことができ、オーバーロード機能を活用することができます。

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

それから、戻り値が演算処理に使われる場合(参照するものがあるように)、ほぼ同じになります。

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

---

自分なら、パラメータを参照して返すオーバーロード関数を作りますね。

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

また、アサインする際にswichを取り除くことができ、オーバーロード機能を活用することができます。

それから、戻り値が演算処理に使われる場合(調べるものがあるように)、ほぼ同じになります。

明示的なオーバーロードと算術演算で、そのままクリア。そうですね、この場合は明らかにオーバーロード=ベターですね、おっしゃるとおりです、ただ質問のために素早く例を作っていたのであまり考えていませんでした(intだけでなくchar, uchar, short, ushort, uint, bool, colorもあるのですべてが単純というわけではありませんが )))))))) 。

ドミトリー・フェドセーエフ

パラメータを参照で返すオーバーロード関数を作るとしたら。


ここで問題になるのは、オーバーロードされたメソッドの 戻り値の型が、オブジェクトの内容に依存することです。

例えば、マルチタイプの配列があります(本がたくさんあるので、例は挙げません)。そしてもちろん、どんな配列にも、適切なインデックスを持つ変数の値を返す[]インデックス演算が必要です。

しかし、変数にはさまざまな種類があります。このインデックスの下には、datetimeやstring、あるいはユーザー定義の型もあり得ます。また、理想を言えば、明示的にパラメータ化しなくても、[]のインデックスを作成する際に、戻り値の型が自動的に適切な型を生成するようにしたいです。私はこの「問題」を次のような方法で解決していました:var[(char)1], var[(short)1], var[(uint)1] etc. しかし、これらの松葉杖はうまくいきません。

 
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:

この場合、p1をp4に割り当てることは(タイプ変更で)できないので、原理的には可能なはずです。

あるいは、配列の場合 - 基本型が1つで異なる型のオブジェクトですが、配列オブジェクト自体がメソッドを持っており、その戻り値の型は対応するインデックスのオブジェクトの型に依存します。
 
同じような質問ですが、メソッドをオーバーロードするとき、(オーバーロードされたメソッドの シグネチャで)戻り値の型が表示されず、パラメータの型だけが表示されるのはなぜですか。
 
Ilya Malev:

この場合、原理的には可能なはずのp1のp4への割り当て(型変更あり)ができません。

あるいは、配列の場合 - 基本型がひとつで異なる型のオブジェクトですが、配列オブジェクト自体がメソッドを持っており、その戻り値の型は対応するインデックスのオブジェクトの型に依存します。

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

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

そう、90%のケースで4バイトで十分なのに、32バイトを送信するのは......。とにかく、それはこのスレッドのポイントではありません、私は目的に興味があります - 誰かが記述された状況で、多かれ少なかれ優雅な解決策を見つけたかもしれません。


p.s. さらに、この質問は、1つのオブジェクト/構造体に異なるタイプのデータを格納することについては全く関係ありません。

 
Ilya Malev:
同じような質問ですが、メソッドをオーバーロードするとき(オーバーロードされたメソッドの シグネチャで)、なぜ戻り値の型が表示されず、パラメータの型だけが表示されるのでしょうか。

メソッドはどのような型を返すかを決めることができません。

 
fxsaber:

メソッドは、どの型を返すかを決めることはできません。

つまり、私が書いたことを繰り返したわけです。問題は、できるかできないかではなく、なぜできないのか、どうすればエレガントに回避できるのか、ということだったのです

 
Ilya Malev:

つまり、私が書いたことを繰り返しているわけです。問題は、できるかできないかではなく、なぜできないのか、どうすれば潔く回避できるのか、ということだったのです。

タイプコントロールができなくなる。C++のリソースに目を通して、これらの質問に対する答えを探してみてください。結構、聞かれることが多いと思います。

理由: