태그 보관물: delegation

delegation

C ++ 대리자는 무엇입니까? 깨끗하지는 않지만 작업하는 코드베이스에 풍부함이 있음을 알았습니다.

C ++에서 델리게이트의 일반적인 아이디어는 무엇입니까? 그들은 무엇이며 어떻게 사용되며 무엇을 위해 사용됩니까?

먼저 ‘블랙 박스’방식으로 그들에 대해 배우고 싶지만, 이런 것들의 내장에 대한 약간의 정보도 훌륭 할 것입니다.

이것은 C ++이 가장 순수하거나 깨끗하지는 않지만 작업하는 코드베이스에 풍부함이 있음을 알았습니다. 나는 그것들을 충분히 이해하기를 바라고 있으므로 그냥 사용할 수 있고 끔찍한 중첩 템플릿 끔찍함을 탐구 할 필요가 없습니다.

이 두 가지 코드 프로젝트 기사는 내가 의미하는 바를 간결하게 설명하지는 않습니다.



답변

C ++에서 델리게이트를 달성하기위한 수많은 선택이 있습니다. 여기 내 마음에 온 것들이 있습니다.


옵션 1 : 펑터 :

함수 객체는 다음을 구현하여 만들 수 있습니다. operator()

struct Functor
{
     // Normal class/struct members

     int operator()(double d) // Arbitrary return types and parameter list
     {
          return (int) d + 1;
     }
};

// Use:
Functor f;
int i = f(3.14);

옵션 2 : 람다 식 ( C ++ 11 만 해당)

// Syntax is roughly: [capture](parameter list) -> return type {block}
// Some shortcuts exist
auto func = [](int i) -> double { return 2*i/1.15; };
double d = func(1);

옵션 3 : 함수 포인터

int f(double d) { ... }
typedef int (*MyFuncT) (double d);
MyFuncT fp = &f;
int a = fp(3.14);

옵션 4 : 멤버 함수에 대한 포인터 (가장 빠른 솔루션)

코드 프로젝트 에서 Fast C ++ Delegate를 참조하십시오 .

struct DelegateList
{
     int f1(double d) { }
     int f2(double d) { }
};

typedef int (DelegateList::* DelegateType)(double d);

DelegateType d = &DelegateList::f1;
DelegateList list;
int a = (list.*d)(3.14);

옵션 5 : 표준 :: 기능

(또는 boost::function표준 라이브러리가 지원하지 않는 경우). 느리지 만 가장 유연합니다.

#include <functional>
std::function<int(double)> f = [can be set to about anything in this answer]
// Usually more useful as a parameter to another functions

옵션 6 : 바인딩 ( std :: bind 사용 )

예를 들어 멤버 함수를 호출하는 데 편리한 일부 매개 변수를 미리 설정할 수 있습니다.

struct MyClass
{
    int DoStuff(double d); // actually a DoStuff(MyClass* this, double d)
};

std::function<int(double d)> f = std::bind(&MyClass::DoStuff, this, std::placeholders::_1);
// auto f = std::bind(...); in C++11

옵션 7 : 템플릿

인수 목록과 일치하는 한 아무 것도 허용하십시오.

template <class FunctionT>
int DoSomething(FunctionT func)
{
    return func(3.14);
}

답변

델리게이트는 객체 인스턴스에 대한 포인터 또는 참조를 래핑하는 클래스, 해당 객체 인스턴스에서 호출 할 객체 클래스의 멤버 메소드 및 해당 호출을 트리거하는 메소드를 제공합니다.

예를 들면 다음과 같습니다.

template <class T>
class CCallback
{
public:
    typedef void (T::*fn)( int anArg );

    CCallback(T& trg, fn op)
        : m_rTarget(trg)
        , m_Operation(op)
    {
    }

    void Execute( int in )
    {
        (m_rTarget.*m_Operation)( in );
    }

private:

    CCallback();
    CCallback( const CCallback& );

    T& m_rTarget;
    fn m_Operation;

};

class A
{
public:
    virtual void Fn( int i )
    {
    }
};


int main( int /*argc*/, char * /*argv*/ )
{
    A a;
    CCallback<A> cbk( a, &A::Fn );
    cbk.Execute( 3 );
}

답변

C ++ 델리게이트 구현의 필요성은 C ++ 커뮤니티에 오랫동안 지속되어 온 것입니다. 모든 C ++ 프로그래머는 다음과 같은 사실에도 불구하고 사용하기를 원합니다.

  1. std::function() 힙 작업을 사용합니다 (심각한 임베디드 프로그래밍에 도달 할 수 없음).

  2. 다른 모든 구현은 이식성 또는 표준 적합성에 대한 양보를 크거나 작게 만듭니다 (여기 및 코드 프로젝트에서 다양한 델리게이트 구현을 검사하여 확인하십시오). 나는 와일드 reinterpret_casts를 사용하지 않는 구현, 사용자가 전달 한 것과 동일한 크기의 함수 포인터를 생성하는 중첩 클래스 “프로토 타입”, 먼저 앞으로 선언과 같은 컴파일러 트릭, typedef를 다시 선언하는 구현을 보지 못했습니다. 이번에는 다른 클래스 또는 유사한 그늘진 기술에서 상속되었습니다. 그것을 구현 한 구현 자에게는 큰 성과이지만 C ++의 진화 방식에 대한 슬픈 증거입니다.

  3. C3 표준 개정이 3 개 이상인 델리게이트가 제대로 처리되지 않았다는 점은 거의 지적되지 않았습니다. (또는 간단한 델리게이트 구현을 허용하는 언어 기능이 부족합니다.)

  4. C ++ 11 람다 함수가 표준에 의해 정의되는 방식 (각 람다는 익명의 다른 유형을 가짐)으로 상황이 일부 유스 케이스에서만 개선되었습니다. 그러나 (DLL) 라이브러리 API에서 델리게이트를 사용하는 유스 케이스의 경우 람다 만으로는 여전히 사용할 수 없습니다. 여기에서 일반적인 기술은 먼저 람다를 std :: function으로 압축 한 다음 API를 통해 전달하는 것입니다.


답변

간단히 말하면 델리게이트는 함수 포인터가 작동하는 방식에 대한 기능을 제공합니다. C ++에는 함수 포인터에 대한 많은 제한이 있습니다. 델리게이트는 배후의 템플릿 불쾌감을 사용하여 원하는 방식으로 작동하는 템플릿 클래스 함수 포인터 유형을 만듭니다.

즉-주어진 기능을 가리 키도록 설정할 수 있으며 언제 어디서나 전달할 수 있습니다.

여기에 좋은 예가 있습니다.


답변

여기에 언급되지 않은 C ++의 대리자 옵션은 함수 ptr 및 컨텍스트 인수를 사용하여 C 스타일을 수행하는 것입니다. 이것은 아마도이 질문을 많은 사람들이 피하려고하는 것과 같은 패턴 일 것입니다. 그러나 패턴은 이식 가능하고 효율적이며 임베디드 및 커널 코드에서 사용할 수 있습니다.

class SomeClass
{
    in someMember;
    int SomeFunc( int);

    static void EventFunc( void* this__, int a, int b, int c)
    {
        SomeClass* this_ = static_cast< SomeClass*>( this__);

        this_->SomeFunc( a );
        this_->someMember = b + c;
    }
};

void ScheduleEvent( void (*delegateFunc)( void*, int, int, int), void* delegateContext);

    ...
    SomeClass* someObject = new SomeObject();
    ...
    ScheduleEvent( SomeClass::EventFunc, someObject);
    ...

답변

표준 C ++의 함수 객체에 해당하는 Windows 런타임 전체 함수를 매개 변수로 사용할 수 있습니다 (실제로는 함수 포인터입니다). 주로 이벤트와 함께 사용됩니다. 대리인은 이벤트 처리기가 많이 이행하는 계약을 나타냅니다. 함수 포인터가 작동하는 방법을 용이하게합니다.


답변