Co to jest delegat C++?

Jaka jest ogólna idea delegata w C++? Czym są, w jaki sposób i do czego służą?

Chciałbym najpierw dowiedzieć się o nich w "czarnej skrzynce" sposób, ale trochę informacji na temat wnętrzności tych rzeczy byłoby również świetne.

To nie jest C++ w jego najczystszym lub najczystszym, ale zauważyłem, że baza kodu, w której pracuję, ma je w obfitości. Mam nadzieję, że zrozumiem je wystarczająco, abym mógł je po prostu wykorzystać i nie musiał zagłębiać się w straszne zagnieżdżony szablon awfulness.

Te dwa w artykułach Code Project wyjaśniają co mam na myśli, ale niezbyt zwięźle:

Author: Peter Mortensen, 2012-03-05

6 answers

Masz niesamowitą liczbę wyborów do osiągnięcia delegatów w C++. Oto te, które przyszły mi do głowy.


Opcja 1: funktory:

Obiekt funkcji może być utworzony przez implementację 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);

Opcja 2: wyrażenia lambda (tylko 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);

Opcja 3: Wskaźniki funkcji

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

Opcja 4: Wskaźnik do funkcji Członkowskich (najszybszy rozwiązanie)

Zobacz Fast C++ Delegate (na projekt Code ).

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

Opcja 5: std:: function

(lub boost::function Jeśli biblioteka standardowa go nie obsługuje). Jest wolniejszy, ale najbardziej elastyczny.

#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

Option 6: binding (using std:: bind)

Umożliwia ustawienie pewnych parametrów z góry, Wygodne wywołanie funkcji member dla przykład.

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

Opcja 7: szablony

Akceptuj wszystko, o ile pasuje do listy argumentów.

template <class FunctionT>
int DoSomething(FunctionT func)
{
    return func(3.14);
}
 185
Author: J.N.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-11 15:04:26

Delegat jest klasą, która zawija wskaźnik lub odniesienie do instancji obiektu, metodę składową klasy tego obiektu, która ma być wywołana na tej instancji obiektu i zapewnia metodę do wywołania tego wywołania.

Oto przykład:

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 );
}
 40
Author: Grimm The Opiner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-05 07:04:31

Potrzeba implementacji delegatów C++ jest długotrwałym kłopotem dla społeczności C++. Każdy programista C++ chciałby je mieć, więc w końcu korzysta z nich pomimo faktu, że:

  1. std::function() wykorzystuje operacje sterty (i jest poza zasięgiem poważnego programowania wbudowanego).

  2. Wszystkie inne wdrożenia ustępują w kierunku przenośności lub standardowej zgodności w większym lub mniejszym stopniu (sprawdź, sprawdzając różne delegaty implementacje tutaj i na codeproject). Muszę jeszcze zobaczyć implementację, która nie używa wild reinterpret_casts, zagnieżdżoną klasę "prototypy", która miejmy nadzieję produkuje Wskaźniki funkcji o takim samym rozmiarze jak ten przekazany przez użytkownika, sztuczki kompilatora, takie jak first forward declare, następnie typedef, a następnie declare ponownie, Tym razem dziedzicząc z innej klasy lub podobnych shady technik. Chociaż jest to wielkie osiągnięcie dla implementatorów, którzy to zbudowali, to nadal jest smutnym świadectwem tego, jak C++ ewoluuje.

  3. Rzadko zwraca się uwagę na to, że obecnie ponad 3 wersje standardu C++ nie zostały odpowiednio zaadresowane. (Lub brak funkcji językowych, które pozwalają na proste implementacje delegatów.)

  4. Przy sposobie definiowania przez standard funkcji lambda w C++11 (każda lambda ma anonimowy, inny typ), sytuacja uległa poprawie tylko w niektórych przypadkach użycia. Ale dla przypadku użycia delegatów w API biblioteki (DLL), lambdas same nadal nie nadają się do użytku. Powszechną techniką jest najpierw spakowanie lambda do funkcji std::, a następnie przekazanie jej przez API.

 19
Author: BitTickler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-29 17:10:28

Bardzo prosto, delegat zapewnia funkcjonalność, jak powinien działać wskaźnik funkcji. Istnieje wiele ograniczeń wskaźników funkcji w C++. Delegat używa jakiegoś zakulisowego szablonu, aby utworzyć szablon-Klasa function-pointer-type-thing, który działa w sposób, w jaki chcesz.

Ie - możesz ustawić je tak, aby wskazywały na daną funkcję, możesz je przekazywać i wywoływać kiedykolwiek i gdziekolwiek chcesz.

Jest tu kilka bardzo dobrych przykładów:

 8
Author: SirYakalot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-10 12:11:35

Opcją dla delegatów w C++, która nie jest tu inaczej wymieniona, jest zrobienie tego w stylu C przy użyciu funkcji ptr i argumentu kontekstowego. Jest to prawdopodobnie ten sam wzór, który wielu zadających to pytanie stara się uniknąć. Ale wzorzec jest przenośny, wydajny i jest użyteczny w kodzie osadzonym i jądrze.

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);
    ...
 4
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-03 18:20:34

Windows Runtime odpowiednik obiektu funkcji w standardowym C++. Można użyć całej funkcji jako parametru(w rzeczywistości jest to wskaźnik funkcji). Jest używany głównie w połączeniu z wydarzeniami. Delegat reprezentuje kontrakt, który podmioty obsługujące zdarzenia znacznie wypełniają. Ułatwia to pracę wskaźnika funkcji.

 1
Author: nmserve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-25 16:03:12