エラー、バグ、質問 - ページ 1183

 
Zeleniy:

Expert Advisorをテスト すると、エラーが発生する

OrderSend 関数の無効なテイクプロフィット

OrderSend エラー 4107

コードに触れずに修正するにはどうしたらよいですか?

の設定で、Takeprofitの増減を試してみてください。
 
mql5:
このオブジェクトには ZeroMemory 関数は使用できません。

なるほど、でもなぜコンパイラはZeroMemoryが 使われているところではなく、クラスが定義されているところでこのエラーを表示するのでしょうか? 混乱してしまいますね。エラーの内容や場所を把握するために、すでに頭を悩ませています。 エラーが正しい場所に表示されるようにしてください。 たとえば、コピーしてはいけない項目を含むオブジェクトをコピーする場合、エラーはクラスのどこかではなく、まさにコピーしている行で発生するのです。

 
meat:

さて、現実的な話ですが、すでに問題が発生しています。静的オブジェクトを使用したコードでした。そこで、一部をダイナミックに置き換えることにしたのです。その結果、比較演算と代入演算が全く異なる動作をするようになった。そして、この問題は、プログラムがコンパイルされ正常に動作し続けるものの、本来の動作には至らないため、発見が困難でした。

私はすぐに問題を理解することができませんでした

class B {};

class A {
public:
        bool operator !=( A* a ) { Print( __FUNCTION__ ); return ( true  );  }
        bool operator !=( B* b ) { Print( __FUNCTION__ ); return ( false );  }
        bool operator >>( A* a ) { Print( __FUNCTION__ ); return ( true  );  }
        bool operator +( A* a )  { Print( __FUNCTION__ ); return ( false  ); }
        bool operator !()        { Print( __FUNCTION__ ); return ( true   ); }
};

void OnStart()
{
        A *a = new A;
        B *b = new B;
        if ( a != a ) Print( "1" );
        if ( a != b ) Print( "2" );
        if ( a >> a ) Print( "3" );
        if ( !a )     Print( "4" );
        delete( a );
        delete( b );
}
このことから、(a != a) はポインタの比較、(a >> a) は演算子 >>( A* ) の呼び出しにつながることがわかります。

矛盾がある。

他のオーバーロードされた演算子(==と!=を除く)のように(a >> a)の動作を変えることはできません。(A)を返すことができず、(A*)しか返せないため、次の構成が不可能になってしまうからです。

class A {
public:
        A *operator >>( string str ) { return ( GetPointer( this ) ); }
};

void OnStart()
{
        A *a = new A;
        a << "1234" << "мы" << "всю ночь" << "тусили"; //множественное применение оператора <<
}

また、ポインタからオブジェクトへの変換操作(*a)がないため、オーバーロードされた演算子を完全に使用することは不可能となる

あとは、(== と !=) の動作を変更するだけです。

ポインタ (== と !=) を互いに、またゼロ番と比較するには (他のポインタ操作は無意味なので)、 (GetPointer) のような特別な関数を導入するか、コンパイラに明示的に型変換を 指定する必要があります。

void OnStart()
{
        A *a = new A;
        B *b = new B;
        if ( ulong(a) != ulong(b) ) Print( "2" ); //хочу сравнить указатели
         if (       a  !=       b  ) Print( "2" ); //хочу вызвать operator !=( B* )

}

このため、オーバーロードされた演算子を本格的に使用する可能性が保たれ、上記の矛盾が解消されることになります

一般的なルールの唯一の合理的な例外は、operator=()のままであるべきです。


class A {
public:
        A *operator =( A* a ) { return ( GetPointer( this ) ); }
};
void OnStart()
{
        A *a = new A;
        a = a; //не должно трактоваться компилятором как вызов operator=( A* ),
                // а должно остаться как присваивание указателю значения
}
 
そしてもちろん、少なくとも演算子には(*a)を使うという提案もある - C++の表記に戻る
class A {
public:
        bool operator !=( A* a ) { Print( __FUNCTION__ ); return ( true  );  }
};

void OnStart()
{
        A *a = new A;
        if (  a !=  a ) Print( 1 ); //сравнение указателей
        if ( *a != *a ) Print( 2 ); //вызов operator !=( A* )
}

は、すべての矛盾を一挙に解消してしまう。

訂正: 実際、矛盾は部分的にしか解消されていません。なぜなら、このような記法 (*a) は、演算子の多重使用の問題 (== と != を除くすべての演算子で正常に機能します) を解決しないためで、ポインター同士の等質/非等質を比較する最善の方法は依然として特別な関数 - またはulong 型への 明示的変換を使うことです。

 
A100さん、メッセージありがとうございます、整理します。
 
コンパイルエラー
class A {
public:
      A( int a1 ) : a3( a1 ) { }
  static int a2;
        int a3;
};
int A::a2 = 1;

void OnStart()
{
        int b = A::a2;  //нормально
        A t1( b );     //нормально
        A t2( A::a2 ); //ошибка компиляции
        A* t3 = new A( A::a2 ); //нормально
}
コンストラクタの静的メンバ引数(new を除く)であれば
 
コンパイラは転送後の #define 内のコメントを許可しない
#define  f( x )                   \
        ( x != 0 &&  /*comment*/\ 
          x != 1 )

これでいいのだ、これで

#define  f( x )       \
        ( x != 0 &&  \ /*comment*/
          x != 1 )
コンパイルエラー
 

ポインターに関するテーマを続けると、ポインターを取る演算子'&' をMQLの標準に追加するのは良いことだと思います。このように、*と &の 演算子を武器に、必要な操作を明示的に定義することができるのです。

if (&a==&b) Print("Указатели равны");
if (*a==*b) Print("Объекты равны");


そして、このアンパサンドについては、まだまだあります。MQLは変数への参照が 不足しており、特にポインタの使用が限られている(クラス・オブジェクトのみ)ことを考慮すると、このようなことはありません。 この関数では、深くネストした構造体要素や多次元配列への アクセスがしばしば必要です。 その都度フルパスを記述しなければならず、非常に面倒なコードになってしまっています。参照を作ることで物事を単純化できますし、時には便宜上ローカルに変数名を「変更」しなければならないこともあります。 しかし、ここで私は何を説明しているのでしょうか。 参照を使うことがいかに便利かはすでに誰もが知っていますが、今は代わりに #define を使わなければならず、これは確かに良くはありません。

また、関数の結果を参照渡しする機能も必要で、例えば、double& Func() { }のようにします。

 

Facebookでは、最近、ブログからの投稿のバックリンクが登場しています。

1

 
meat:

ポインターをテーマに、MQLにポインターを取る標準的な演算子'&'を追加すると良いでしょう。このように、*と &の 演算子を武器に、必要な操作を明示的に定義することができるようになるのです。

メンバ関数の参照に(*a)だけを採用しても、明確な利点はなく、むしろ演算子を単純明快に使うことができなくなる。

class A {
public:
        A *operator >>( string str ) { Print( __FUNCTION__); return ( GetPointer( this ) ); }
};

void OnStart()
{
        A *a = new A;
        a << "1234" << "мы" << "всю ночь" << "тусили"; //простая и понятная запись

あなたの提案を考慮して書き直してみてください。

void OnStart()
{
        A *a = new A;
        *(*(*(*a << "1234") << "мы") << "всю ночь") << "тусили"; //запутанная запись
}

演算子 <<(...) はオブジェクトへのポインタしか返さないので、ポインタの代わりにオブジェクトそのものを使うことはできません。

ポインターを使った操作で意味のないものは?- 演算子の複数使用の可能性を維持するために、演算子のオーバーロード自体が意味を失うため、それらは無視され、特別な関数(例えば、bool ComparePointer( a,b) )に入れられるべきです。