Dydaktyka:
FeedbackQLineEdit * le = new QLineEdit; // wskaźnik na funkcję z klasy: void (QLineEdit::*leMethod1) () = &QLineEdit::clear; // wywołanie takiego wskaźnika na rzeczy obiektu le: (le->*leMethod1)(); // to samo, z argumentem: void (QLineEdit::*leMethod2) (bool) = &QLineEdit::setEnabled; (le->*leMethod2)(true);
Wyjaśnienie:
<wynik> (*) (<argumenty>)
, np: void (*) (int)
← typ dla zwykłej funkcji<wynik> (<Klasa>::*) (<argumenty>)
, np: void (A::*) (int)
← typ dla metody z obiektu<wynik> (<Klasa>::*nazwa) (<argumenty>)
, np: void (A::*m) (int)
← zmienna powyższego typutemplate <typename T> struct opakowanie { T * obiekt; void (T::*metoda) (bool); void operator()(bool arg){ (obiekt->*metoda)(arg); } }; void someCode(){ QLineEdit * le = new QLineEdit; opakowanie<QLineEdit> box {le, &QLineEdit::setEnabled}; box(true); }
#include <functional> void someCode(){ QLineEdit * le = new QLineEdit; auto box = std::bind(&QLineEdit::setEnabled, le, std::placeholders::_1); box(true); std::function<void (bool)> func = std::bind(&QLineEdit::setEnabled, le, std::placeholders::_1); func(true); // box i func są różnych typów (func opakowuje box) }
Formalnie bind to częściowe wykonanie metody
Dostępny w boost (boost::bind
) od 2001 roku, włączony w standard C++11
W środku std::bind w GCC działa podobnie jak powyższy przykład; identyfikacja typu przez gdb:
(gdb) ptype box type = struct std::_Bind<std::_Mem_fn<void (QWidget::*)(bool)>(QLineEdit*, std::_Placeholder<1>)> [with _Signature = std::_Mem_fn<void (QWidget::*)(bool)> (QLineEdit *, std::_Placeholder<1>)] : public std::_Weak_result_type<std::_Mem_fn<void (QWidget::*)(bool)> > { private: std::_Mem_fn<void (QWidget::*)(bool)> _M_f; std::tuple<QLineEdit*, std::_Placeholder<1> > _M_bound_args; public: _Bind(const std::_Bind<std::_Mem_fn<void (QWidget::*)(bool)>(QLineEdit*, std::_Placeholder<1>)> &); _Bind(<unknown type in /home/user/build-test-Desktop_qt5-Debug/test, CU 0x42cc0, DIE 0x4e548>); void operator()<bool, void>(<unknown type in /home/user/build-test-Desktop_qt5-Debug/test, CU 0x42cc0, DIE 0x4e57b>); void _Bind<QLineEdit*&, std::_Placeholder<1> const&>(<unknown type in /home/user/build-test-Desktop_qt5-Debug/test, CU 0x42cc0, DIE 0x4e5ae>, QLineEdit *&, const std::_Placeholder<1> &); private: void __call<void, bool&&, 0ul, 1ul>(<unknown type in /home/user/build-test-Desktop_qt5-Debug/test, CU 0x42cc0, DIE 0x4e605>, std::_Index_tuple<0ul, 1ul>); }
#include <unistd.h> #include <functional> using namespace std::placeholders; void someCode(){ char buf[255]; std::function<ssize_t (int)> simpleRead = std::bind(read, std::placeholders::_1, buf, 255); simpleRead(0); std::function<ssize_t (void*, size_t)> stdinRead = std::bind(read, 0, std::placeholders::_1, std::placeholders::_2); stdinRead(buf, 255); }
Argumenty można podawać przez wartość lub jako referencja opakowane w std::ref
/ std::cref
.
QLineEdit *le = new QLineEdit; // 1) stara składnia connect jest static, nie ma potrzeby definiowania wskaźnika na metodę z klasy: QMetaObject::Connection (*method1) (const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType) = &QObject::connect; method1(le, SIGNAL(returnPressed()), le, SLOT(clear()), Qt::AutoConnection); // 2) nowa składnia poza tym ze też jest static, to jest oparta na template'ach, więc trzeba jakiś zrealizować: QMetaObject::Connection (*method2) (const QLineEdit *, void (QLineEdit::*)(), const QLineEdit *, void (QLineEdit::*)(), Qt::ConnectionType) = &QObject::connect; method2(le, &QLineEdit::returnPressed, le, &QLineEdit::clear, Qt::AutoConnection); // 3) lepiej to wygląda z typedef: typedef QMetaObject::Connection (*newtype) (const QLineEdit *, void (QLineEdit::*)(), const QLineEdit *, void (QLineEdit::*)(), Qt::ConnectionType); newtype method3 = &QObject::connect; method3(le, &QLineEdit::returnPressed, le, &QLineEdit::clear, Qt::AutoConnection);