2013-09-03 12 views
5

Krótko mówiąc, czy istnieje prosty/zdefiniowany sposób traktowania obiektów funkcyjnych/lambd i funkcji składowych w uproszczony sposób?Używanie std :: function/mem_fn w C++ 11 z funkcjami składowymi

Jeśli rozumiem dobrze, jeśli mogę użyć std :: mem_fn, muszę przekazać obiekt odpowiedniego typu do wywołania funkcji, tj

Object o; 
ftncall std::mem_fun(&Object::function); 
ftncall(o); 

Idealnie byłoby jakiś sposób „dołączyć "o do tego obiektu funkcji, być może jako std::weak_ptr, więc wiemy, że o został usunięty. Na przykład, gdyby nie było sposobu, aby zrobić coś niejasno tak:

Object o; 
ftncall std::mem_fn(&Object::function, o); // Or maybe std::mem_fn<Object> 
ftncall(); 

Teraz, oczywiście, to nie istnieje (według mojej wiedzy). Czy istnieje sposób na owijanie std :: mem_fn w taki sposób, że nie tracę ogólności (i uprzejmości) std :: mem_fn, ale mogę 'dołączyć' o, I nadal dobrze grać z innym typem funkcji, jak std :: function? Idealnie byłoby nadal używać operator() w sposób jaki robię z funkcją std ::.

Obecnie najlepszym rozwiązaniem mogę pomyśleć, to klasa, która wygląda następująco:

template<class T> 
class MemFunWrapper { 
public: 
    MemFunWrapper(T* t, std::mem_fun funct) : m_t(t), m_function(funct) {} 

    std::mem_fun operator*() { return m_function; } 
    T* get() { return m_t; } 
private: 
    T* m_t; 
    std::mem_fun m_function; 
} 

Następnie można go używać wygląda następująco:

(*MemFunWrapper)(MemFunWrapper->get(), args...); 

Ale to wydaje się dość nieporęczny do mnie. Musiałabym również stworzyć równoważną klasę dla funkcji std ::, która byłaby użyta w analogiczny sposób, a to wydaje się głupie, ponieważ mogę już po prostu użyć funkcji std ::. Idealnie byłoby też móc używać produktu końcowego, nie wiedząc, czy dzwonię do funkcji członkowskiej, czy do zwykłej funkcji. Wiem, że dużo zadaję - każdy kierunek byłby pomocny. Wielkie dzięki!

Odpowiedz

10

Co szukasz jest std :: wiążą zamiast std :: mem_fn:

#include <iostream> 
#include <functional> 

struct Object 
{ 
    void member() 
    { 
    std::cout << "yay!" << std::endl; 
    } 
}; 

int main() 
{ 
    Object o; 
    auto fn = std::bind(&Object::member, o); 
    fn(); 
} 

FWIW: Jest proposal dodawania przeciążenie std :: mem_fn akceptując obiekt do włączenia w C++ 14.

+1

Dlaczego dziękuję - być może spełniłeś wszystkie moje nadzieje i marzenia! –

+0

Nie powinno się linii 'auto fn = std :: bind (& Object :: member, o);' to 'auto fn = std :: bind (& Object :: member, &o);', zwracaj uwagę na drugi argument na 'std: : bind ' –

+0

Zależy od twojej intencji Obie są użyteczne w różnych okolicznościach – goji

8

w C++ 11, zwykle znaleźć to najłatwiej zrobić z lambdas:

std::shared_ptr<Object> o; 
auto ftncall = [o](){ if (o) o->function(); } 
ftncall(); 

Jeśli potrzebujesz typu skasowaniu, po prostu wepchnąć go do std::function<void()>.

Lambdas w C++ 11 może wykonać tę samą pracę, co bind, bez konieczności korzystania z funkcji bibliotecznych, a ja osobiście uważam, że są bardziej czytelne.

Istnieje kilka sytuacji, w których bind może wykonać lepszą pracę w C++ 11, ale są to przypadki narożne w tym miejscu (w C++ 1y, więcej zakrętów również zostanie obciętych).

+0

Po prostu z ciekawości, mógłbyś pokazać mi kilka przykładów' std :: bind' jest lepszy w C++ 11? Zastanowiłem się przez jakiś czas ale mogłem nie ma żadnych, czy jest to związane z brakiem polimorficznej lambda? – Sungmin

+1

@Sungmin 'bind' obsługuje perfekcyjne przekazywanie, a lambdy nie.Lambda nie może być polimorficzna, natomiast "bind" może. Lambda ma ustalony typ zwrotu: "bind" może się różnić, jeśli przekażesz go funktorowi z wieloma przeciążeniami. 'bind' wspiera owijanie funktorów wariackich i pozostałe warianty, lambda nie. 'bind's może być wywołany w nieocenionych kontekstach, takich jak' decltype', użyteczne dla 'auto foo() -> decltype (bind (bla)): podczas gdy typ jest rozwarty, nie jest magią jak labmda. To są te, które mogę wymyślić z mojej głowy. Ponad połowa z nich zniknęła w C++ 1y. – Yakk

+0

Niezwykle pomocny - wydaje się to "łatwiejsze", jak mówisz, ale dobrze jest wiedzieć, że nadal będę musiał używać "bind", jeśli zamierzam używać polimorficznych funkcji - prawdopodobnie najbardziej prawdopodobnych sytuacji, które mogłyby spowodować przynajmniej dla mnie. –

Powiązane problemy