На домашней странице Бьярна Страуструпа ( FAQ по C ++ 11 ):
struct X { int foo(int); };
std::function f;
f = &X::foo; //pointer to member
X x;
int v = f(&x, 5); //call X::foo() for x with 5
Как это сделать Работа? Как std :: function вызывает функцию-член foo ?
Параметр шаблона: int (X *, int)
, is & X :: foo
преобразован из указателя на функцию-член в указатель на функцию-не ?!
(int(*)(X*, int))&X::foo //casting (int(X::*)(int) to (int(*)(X*, int))
Чтобы уточнить: я знаю, что нам не нужно приводить какие-либо указатель на использование std :: function , но я не знаю, как внутренности std :: function обрабатывают эту несовместимость между указателем на функцию-член и указатель на функцию, не являющуюся членом . Я не Не знаю, как стандарт позволяет нам реализовать что-то вроде std :: function !
Получив помощь от других ответов и комментариев, а также прочитав исходный код GCC и стандарт C ++ 11, я обнаружил, что можно анализировать тип функции (его тип возврата и его типы аргументов ) с использованием частичной специализации шаблона и перегрузка функции .
Ниже приводится простой (и неполный) пример реализации чего-то вроде std :: function
:
template<class T> class Function { };
// Parse the function type
template<class Res, class Obj, class... ArgTypes>
class Function<Res (Obj*, ArgTypes...)> {
union Pointers {
Res (*func)(Obj*, ArgTypes...);
Res (Obj::*mem_func)(ArgTypes...);
};
typedef Res Callback(Pointers&, Obj&, ArgTypes...);
Pointers ptrs;
Callback* callback;
static Res call_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
return (*ptrs.func)(&obj, args...);
}
static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
return (obj.*(ptrs.mem_func))(args...);
}
public:
Function() : callback(0) { }
// Parse the function type
Function(Res (*func)(Obj*, ArgTypes...)) {
ptrs.func = func;
callback = &call_func;
}
// Parse the function type
Function(Res (Obj::*mem_func)(ArgTypes...)) {
ptrs.mem_func = mem_func;
callback = &call_mem_func;
}
Function(const Function& function) {
ptrs = function.ptrs;
callback = function.callback;
}
Function& operator=(const Function& function) {
ptrs = function.ptrs;
callback = function.callback;
return *this;
}
Res operator()(Obj& obj, ArgTypes... args) {
if(callback == 0) throw 0; // throw an exception
return (*callback)(ptrs, obj, args...);
}
};
Использование:
#include <iostream>
struct Funny {
void print(int i) {
std::cout << "void (Funny::*)(int): " << i << std::endl;
}
};
void print(Funny* funny, int i) {
std::cout << "void (*)(Funny*, int): " << i << std::endl;
}
int main(int argc, char** argv) {
Funny funny;
Function<void(Funny*, int)> wmw;
wmw = &Funny::print; // void (Funny::*)(int)
wmw(funny, 10); // void (Funny::*)(int)
wmw = &print; // void (*)(Funny*, int)
wmw(funny, 8); // void (*)(Funny*, int)
return 0;
}
g ++, похоже, имеет объединение, которое может содержать любой указатель на функцию, указатель на член или указатель void, который, вероятно, указывает на функтор. Добавьте перегрузки, которые соответствующим образом отмечают, какой член объединения является действительным, и тяжелое приведение к супу, и тогда он работает ...
Это не указатели на функции. Для этого существует std :: function. Он обертывает любые вызываемые типы, которые вы ему даете. Вы должны проверить boost :: bind - он часто используется, чтобы сделать указатели функций-членов вызываемыми как (this, args).
Как это происходит (я считаю), оставлено неопределенным (но у меня здесь нет копии стандарта).
Но, учитывая все различные возможности, которые необходимо раскрыть, у меня такое чувство, что расшифровать точное определение того, как это работает, будет очень сложно: поэтому я не собираюсь пытаться.
Но я думаю, вы хотели бы знать, как работают функторы, и они относительно просты. Вот небольшой пример.
Это объекты, которые действуют как функции.
Они очень полезны в коде шаблона, поскольку часто позволяют взаимозаменяемо использовать объекты или функции.Однако самое замечательное в функторах - это то, что они могут удерживать состояние (своего рода замыкание для бедняков).
struct X
{
int operator()(int x) { return doStuff(x+1);}
int doStuff(int x) { return x+1;}
};
X x; // You can now use x like a function
int a = x(5);
Вы можете использовать тот факт, что функтор удерживает состояние, чтобы хранить такие вещи, как параметры или объекты, или указатель на методы-члены (или любую их комбинацию).
struct Y // Hold a member function pointer
{
int (X::*member)(int x);
int operator(X* obj, int param) { return (obj->*member)(param);}
};
X x;
Y y;
y.member = &X::doStuff;
int a = y(&x,5);
Или даже пойти дальше и связать параметры. Итак, теперь все, что вам нужно предоставить, - это один из параметров.
struct Z
{
int (X::*member)(int x);
int param;
Z(int (X::*m)(int), int p) : member(m), param(p) {}
int operator()(X* obj) { return (obj->*member)(param);}
int operator()(X& obj) { return (obj.*member)(param);}
};
Z z(&X::doStuff,5);
X x;
int a = z(x);