関数がそうでない場合static
、非メンバー関数ポインターを受け入れる関数に入力で渡すことはできません。
非メンバー関数には、メンバー関数が呼び出されているオブジェクトを指す最初のパラメーターとしてstatic
の暗黙のポインターがあると考えてください。ClassName
struct X
{
static void foo() { } // Does not have an implicit "this" pointer argument
void bar() { } // Has an implicit "this" pointer argument
};
int main()
{
void (*f)() = &X::foo; // OK: foo is static
void (*g)() = &X::bar; // ERROR! bar is non-static
}
ここではstd::bind()
、結果が関数ポインターに変換できないため、機能しません。ラムダは関数ポインターに変換できますが、キャプチャーされていない場合に限ります(ここでのラムダは、メンバー関数を呼び出すためにオブジェクトをキャプチャーする必要があります)。
したがって、唯一の(醜い)回避策は、グローバルポインタ変数を介して利用可能なオブジェクトのメンバー関数を呼び出すグローバルアダプタ関数を使用することです。関数を呼び出す前に、グローバルポインタ変数が設定されます。
struct X
{
void bar() { }
};
void function_taking_a_function_pointer(void (*f)())
{
// Do something...
f();
}
X* pX = nullptr;
void bar_adapter()
{
pX->bar();
}
int main()
{
X x; // Some object I want to invoke the member function bar() on...
pX = &x; // Set the global pointer and invoke the function...
function_taking_a_function_pointer(bar_adapter);
}
bar_adapter
必要に応じて、関数テンプレートに変換し、メンバー関数へのポインターをテンプレート引数として渡すことで、これを少し柔軟にすることができます。
template<typename T, void (T::*mf)()>
void adapter()
{
(pX->*mf)();
}
使用方法は次のとおりです。
#include <iostream>
struct X
{
void foo() { std::cout << "X::foo()" << std::endl; }
void bar() { std::cout << "X::bar()" << std::endl; }
};
void function_taking_a_function_pointer(void (*f)())
{
// Do something...
f();
}
X* pX = nullptr;
template<typename T, void (T::*mf)()>
void adapter()
{
(pX->*mf)();
}
int main()
{
X x; // Some object I want to invoke the member function bar() on...
pX = &x; // Set the global pointer and invoke the function(s)...
function_taking_a_function_pointer(adapter<X, &X::foo>);
function_taking_a_function_pointer(adapter<X, &X::bar>);
}
最後に、これが実際の例です。