mql5 언어의 특징, 미묘함 및 작업 방법 - 페이지 234

 
fxsaber #:

기간을 측정하고 결과를 얻습니다. TRADE_ACTION_MODIFY에서 이런 일이 발생했습니다.

어디서, 어디에서, 무엇을, 어떤 조건에서 측정 되었습니까?

그냥 주문 보내기 동기화 수정하고 바로 다음 작업으로 5 초 ???

매우 이상하고, 무섭고, 불가능한 결과 - 테스트를 다시 확인해야 합니다.

 
Maxim Kuznetsov #:

어디서, 어디에서, 무엇을, 어떤 조건에서 측정했습니까?

OrderSendAsync MODIFY와 바로 다음 작업으로 5초 ????

매우 이상하고, 무섭고, 가능성이 없는 결과 - 테스트를 다시 확인해야 합니다.

함수 전후의 시간을 측정하고 차이를 계산하여 5 초를 얻었습니다. 전투 고문에서는 모든 것이 측정되므로 비정상적인 상황을 분류 할 수있는 더 많은 정보가 있습니다. 이것을 보았습니다.

 
빈 구조는 자손에게 적절한 할당 연산자를 부여합니다.
struct BASE {};

template <typename T>
struct A : public BASE
{
  T Tmp;
};

void OnStart()
{  
  A<double> d;
  A<int> a = d;
}
 

내부에 서로 다른 행동 규칙을 부여할 수 있지만 서로 동일하게 조작할 수 있는 구조를 만들어야 했습니다.

이 예제에서 사용된 기술은 공식화되었습니다.

struct NUMBERS
{
  int Num1;
  int Num2;
};

template <typename T>
struct A : public NUMBERS
{
  int Get1() { return(T::Action1(this.Num1, this.Num2)); }
  int Get2() { return(T::Action2(this.Num1, this.Num2)); }
};

class ADDITION
{
public:
  static int Action1( const int Num1, const int Num2 ) { return(Num1 + Num2); }
  static int Action2( const int Num1, const int Num2 ) { return(Num1 - Num2); }
};

class MULTIPLICATION
{
public:  
  static int Action1( const int Num1, const int Num2 ) { return(Num1 * Num2); }  
  static int Action2( const int Num1, const int Num2 ) { return(Num1 / Num2); }  
};

void OnStart()
{
  NUMBERS a = {5, 2};  
  
  A<ADDITION> b = a;
  Print(b.Get1()); // 7
  Print(b.Get2()); // 3
  
  A<MULTIPLICATION> c = b;
  Print(c.Get1()); // 10
  Print(c.Get2()); // 2
}


안타깝게도 저는 왜 OOP 언어에 정적 메서드에 대한 인터페이스가 없는지 이해하지 못했습니다.

interface A
{
public:
  static void Func() {} // 'Func' - cannot be declared static
};
 
fxsaber 정적 메서드에 대한 인터페이스가 없는지 이해하지 못했습니다.

그런 공포를 만들어야 했죠.

#define  INTERFACE \
  static void Func();
  
class A
{
public:
  INTERFACE
  
  static void f() { Print(typename(A)); }
};

class B
{
public:
  INTERFACE
  
  static void g() { Print(typename(B)); }  
};

static void A::Func() {}
static void B::Func() {}

template <typename T>
void Tmp() { T::Func(); }

void OnStart()
{
  Tmp<A>();
  Tmp<B>();
}
 
fxsaber 메서드에 대한 인터페이스가 없는지 이해하지 못했습니다.

어떻게 생각하시나요?

모든 함수는 .text 세그먼트에 주소가 있습니다.

모든 멤버 함수(메서드)는 암시적으로 이 포인터를 첫 번째 매개변수로 받아들입니다.

정적 메서드는 이 포인터를 받아들이지 않으며, 사실상 일반 함수에 해당하는 구문론적 "설탕"입니다.

가상 함수가 호출되면 실행 가능한 함수의 주소는 가상 함수가 선언된 클래스에 암시적으로 포함되어 있는 포인터인 가상 함수 테이블에서 가져옵니다. 실행 가능 함수에 대한 포인터의 초기화는 객체의 인스턴스를 생성할 때 발생하며, 로직은 다음과 같습니다(모든 초보자가 명확하게 이해할 수 있도록 일부러 mql로 작성했습니다):

class Base;
class A;
class B;

void FooClassA(Base* p);
void FooClassC(Base* p);

typedef void(*_Foo)(Base*);

class Base{
public:
   Base(): foo(NULL){}
   void Foo() {foo(&this);}
protected:
   _Foo foo;
};

class A: public Base{
public:
   A():a(100){foo = FooClassA;}
   int a;
};

class B: public A{
public:
   B():b(-100){}
   int b;
};

class C: public B{
public:
   C(){foo = FooClassC;}
   int Get() {return a+b;}
};

void FooClassA(Base* p){PrintFormat("%s: %i",__FUNCTION__,dynamic_cast<A*>(p).a);}
void FooClassC(Base* p){PrintFormat("%s: %i",__FUNCTION__,dynamic_cast<C*>(p).Get());}

void OnStart(){
   A a;
   B b;
   C c;
   Base* p = &a;
   p.Foo();
   p=&b;
   p.Foo();
   p=&c;
   p.Foo();
}

당연히 실제로는 모든 것이 이와 같지는 않지만 함수에 대한 포인터의 초기화 메커니즘은 정확히 이와 같습니다. 따라서 "전혀"라는 단어에서 컴파일 된 언어에서 원하는 방식으로 수행 할 수있는 방법은 없습니다.

C++에는 이러한 템플릿 마법이 있습니다:

#include <iostream>
#include <variant>

struct A
{
    int a = 100;
    int Get() { return a; }
};

struct B :A
{
    int b = -100;
};

struct C :B
{
    int Get() { return a + b; }
};

using BaseImpl = std::variant<A, B, C>;
struct Base : BaseImpl
{
    using BaseImpl::BaseImpl;
    int Get() { return std::visit([](auto&& arg) { return arg.Get(); }, static_cast<BaseImpl&>(*this)); }
};

int main()
{
    Base a = A();
    Base b = B();
    Base c = C();
    std::cout << a.Get() << ", " << b.Get() << ", " << c.Get() << std::endl; //100, 100, 0
    b = C();
    std::cout << a.Get() << ", " << b.Get() << ", " << c.Get() << std::endl; //100, 0, 0
    return 0;
}
 
Vladimir Simakov #:

모든 함수는 .text 세그먼트에 주소가 있습니다.

모든 멤버 함수(메서드)는 암시적으로 이 포인터를 첫 번째 매개변수로 받아들입니다.

정적 메서드는 이 포인터를 받아들이지 않으며, 사실상 일반 함수에 해당하는 구문론적 "설탕"입니다.

가상 함수가 호출되면 실행 가능한 함수의 주소는 가상 함수가 선언된 클래스에 암시적으로 포함되어 있는 포인터인 가상 함수 테이블에서 가져옵니다. 실행 가능 함수에 대한 포인터의 초기화는 객체의 인스턴스를 생성할 때 발생하며, 로직은 다음과 같습니다(모든 초보자에게 명확하게 설명하기 위해 mql로 작성했습니다):

물론 실제로는 이와 같지 않지만 함수에 대한 포인터의 초기화 메커니즘은 정확히 이와 같습니다.

예제와 함께 자세한 설명을 해주셔서 감사합니다!

 
Vladimir Simakov #:

이에 대해 어떻게 생각하시나요?

인터페이스의 가능성에 대한 저의 아쉬움에 대해 말씀하시는 거라면요. 저는 클래스/구조체에 구문 제한만 적용하고 싶습니다. 즉, 컴파일 단계에서만 동일한 const 수정자를 사용하는 것처럼 말입니다. 간단히 말해 자기 통제를 위해서입니다.

"전혀"라는 단어에서 알 수 있듯이 컴파일된 언어에서 원하는 것을 할 수 있는 방법은 없습니다.

저는 위에 목발을 썼습니다. 그런 경우를 위해 이미 내장된 무언가를 얻고 싶었습니다.

 

트레이딩, 자동매매 시스템 및 트레이딩 전략 테스트 포럼

메타트레이더 5 빌드 3950의 새 버전: 터미널에서 출금/입금 및 거래 보고서 업데이트

fxsaber, 2023.09.19 23:25

오류를 제거하는 방법은?
#define  TEMPNAME(A) A##__LINE__
#define  TEMPNAME2(A) Tmp##A
   
void OnStart()
{
  int TEMPNAME(Tmp); // variable 'Tmp__LINE__' not used
  
  int TEMPNAME2(__LINE__); // 'Tmp__LINE__' - variable already defined
  int TEMPNAME2(__LINE__); // variable 'Tmp__LINE__' not used
}
#define  TEMPNAME2(A) Tmp##A
#define  TEMPNAME1(A) TEMPNAME2(A)
   
void OnStart()
{
  int TEMPNAME1(__LINE__);
  int TEMPNAME1(__LINE__);
}

처음 __LINE__/__COUNTER__가 마코 내부에 텍스트로 전달되면 두 번째는 숫자로 전달됩니다.

 
아마 자전거를 발명했을지도 모르겠네요. 누군가 더 우아한 해결책을 알고 있다면 공유해 주세요.

이전에는 (이전 컴파일러 빌드에서는) 선언 전에 클래스를 사용할 수 있었습니다:
class A;

class B
{
   public: A a;
   public: int Val;
};

class A
{
   public: B * b;
   public: int Test() {return b.Val + 1;}
};

//+------------------------------------------------------------------+
//|                                                                                |
//+------------------------------------------------------------------+
void OnStart()
{
   B b;
   b.a.b = GetPointer(b);
   b.Val = 1;
   
   Print(b.a.Test());
}
하지만 이제 컴파일할 때 오류가 발생합니다:
정의되지 않은 클래스 'A'를 사용할 수 없습니다.

이 오류를 해결하기 위해 두 가지 해결책을 생각해냈습니다.

1. 베이스 클래스를 통해:

class A0
{
   public: virtual int Test() {return 0;}
};

class B
{
   public: A0 * a;
   public: int Val;
};

class A: public A0
{
   public: A(B * source) {b = source;}
   public: B * b;
   public: virtual int Test() {return b.Val + 1;}
};

//+------------------------------------------------------------------+
//|                                                                                |
//+------------------------------------------------------------------+
void OnStart()
{
   B b;
   A a(GetPointer(b));
   
   b.a = GetPointer(a);
   b.Val = 1;
   
   Print(b.a.Test());
}

2. 중첩 클래스를 통해:

class B
{
   class A
   {
      public: B * b;
      public: int Test() {return b.Val + 1;}
   };

   public: A a;
   public: int Val;
};

//+------------------------------------------------------------------+
//|                                                                                |
//+------------------------------------------------------------------+
void OnStart()
{
   B b;
   b.a.b = GetPointer(b);
   b.Val = 1;
   
   Print(b.a.Test());
}

제 생각에는 두 번째 해결책이 첫 번째 해결책보다 더 최적이라고 생각합니다.
사유: