2010-09-01 3 views
11

Предоставляет ли C++ 11 делегаты?Делегат в C++ 11

Если нет, то какой лучший (самый эффективный) способ сделать что-то подобное на C++? Boost.Signals? FastDelegate? Что-то другое?

+0

Что случилось с указателями на функции? – alternative

+0

Я не могу использовать его с помощью метода класса:/ – dot222

+0

да, вы можете http: //www.parashift.com/C++ - faq-lite/pointers-to-members.html, но есть, вероятно, лучшие вещи для использования, например. Функции C++ не должны быть методами, или вы можете превратить класс в функтор –

ответ

14

Вы можете получить делегат типа семантики с помощью bind связать функцию-член к экземпляру класса:

#include <functional> 

struct C 
{ 
    void Foo(int) { } 
}; 

void Bar(std::function<void(int)> func) 
{ 
    func(42); // calls obj.Foo(42) 
} 

int main() 
{ 
    using namespace std::placeholders; 

    C obj; 
    Bar(std::bind(&C::Foo, obj, _1)); 
} 

В этом примере Bar() принимает все, что имеет один int параметр и возвращает void.

В main() мы привязываем указатель на функцию-член C::Foo к примеру C с именем obj. Это дает нам объект, который можно вызвать с помощью одного параметра int и который возвращает void.

С этим объектом мы звоним Bar(), а Bar() делает звонок obj.Foo(42).

+0

+1, или вы можете просто превратить C в функтор. –

+0

@jk: Только иногда. Очевидно, что в этом случае вы могли бы, но у меня не было много классов в моем приложении, которые имеют только одну функцию-член :-) –

-1

Механизм C всегда был указателем функции & baton (за исключением qsort() и bsearch(), которые не принимали эстафетную палочку).

Таким образом, всегда можно передать объект класса в качестве дубинки.

т.д .:

class tp { 
    public: 
     tp() { n = 0; } 
     void m(int z) { printf("%d is %d\n", n++, z++); } 
     int n; 
}; 

void higher_func(int *opx, int cnt, void *handler(int itm, void *baton), void *baton) 
{ 
    for (int i = 0; i < cnt; i++) 
     handler(opx[itm], baton); 
} 

/* You would need to provide this stub -- potentially templateable */ 
void translate_baton(int itm, void *baton) { ((tp *)baton)->m(itm); } 

/* used like so: */ 
int main() 
{ 
    int array[7]; 

    //... 
    tp cx; 
    higher_func(array, 7, translate_baton, &cx); 
} 
+5

Этот вопрос не о C: механизм C доступен на C++, но это не делает его лучший вариант. –

+0

Я много работаю с делегатами в .NET и считаю, что таким образом избавил бы меня от неприятностей на пути делегатов, чем наоборот. – Joshua

0

Вам не обязательно нужно ждать C++ 0x. Вы можете реализовать делегатов почти так же в текущем стандарте C++ 03. Вам просто нужно перегрузить оператор(), так как вы можете позвонить MyObjectFunctor functor; functor();, а поскольку функтор является объектом, вы можете передать его как делегат/объект в функции;

Текущая версия STL определяет заголовок <algorithm>, который предоставляет функции, готовые для использования с функторами/Lambdas/Delegates.

простой пример функтора.

struct FunctorDelegate 
{ 
    // as so to delegate as a function that takes an int input 
    void operator()(int) 
    { 
     // do what I want 
    } 
}; 

int main() 
{ 
    //... do some stuffs with an std::vector<int> aRange; 
    FunctorDelegate functor; 
    std::for_each(aRange.begin(), arange.end(), functor); 
} 
+0

. Что могут сделать делегаты - это возможность хранить, например, 'int A :: func1 (int, int)' или 'int B :: func2 (int, int)' в переменной (например, 'f'), поэтому что его можно назвать похожим на 'int v = f (a, 12, 34);' или 'int v2 = f (b, 42, 24);'. В вашем примере может быть вызван функтор, но он не может рассматриваться как абстракция типа функции 'void (int)'. –

2

Вам не нужен C++ 0x. в <functional> у вас есть bind1stbind2ndmem_fun и mem_fun_ref. У вас также есть Boost.Bind, который обобщает все перечисленные выше функции (IIRC).

Переход из памяти ...

vector<Foo> foo = makeVector(); 
vector<Foo*> foop = makeVectorP(); 
vector<Bar> bar1,bar2,bar3,bar4; 
transform(foo.begin(), foo.end(), back_inserter(bar1), mem_fun_ref(&Foo::getBar)); 
transform(foop.begin(), foop.end(), back_inserter(bar2), mem_fun(&Foo::getBar)); 
transform(foo.begin(), foo.end(), back_inserter(bar3), bind1st(&bar_from_foo)); 
transform(foo.begin(), foo.end(), back_inserter(bar4), boost::bind(&bar_from_foo, _1)); 
+6

bind1st, bind2nd, mem_fun и mem_fun_ref устарели в C++ 11. –

1

Хотя std::function работает хорошо, я хотел бы отметить, это хороший кусок кода делегата, написанный here (в том числе, например, использование!). Следуя рекомендациям и ответам, вы можете прочитать все о том, как этот класс Delegate построен и почему он может быть быстрее, чем std::function.

Отметим также, что мой вопрос here для проблемы я столкнулся с ним на VS 2015.