Jeśli funkcja nie jest static
, nie można przekazać jej do wejścia funkcji, która akceptuje wskaźnik funkcji nie będący członkiem.
Należy uznać, że funkcja składowa inna niż static
ma domyślny wskaźnik do ClassName
jako swój pierwszy parametr, który wskazuje obiekt, na którym wywoływana jest funkcja składowa.
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
}
Tutaj nawet nie std::bind()
będzie działać, ponieważ wynik nie jest zamienny do wskaźnika funkcji. Lambdy są przekształcalne na wskaźniki funkcji, ale tylko wtedy, gdy nie przechwytują (a lambda w tym miejscu musiałaby przechwycić obiekt, aby wywołać funkcję członka).
Dlatego jedynym (brzydkim) obejściem jest posiadanie globalnej funkcji adaptera, która wywołuje funkcję składową obiektu, który jest dostępny za pośrednictwem globalnej zmiennej wskaźnika. Zmienna wskaźnik globalny jest ustawiony przed wywołaniem funkcji:
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);
}
Jeśli chcesz, możesz zrobić to nieco bardziej elastyczne obracając bar_adapter
do funkcji szablon i przepuszczenie wskaźnik do członków funkcję jako argument szablonu:
template<typename T, void (T::*mf)()>
void adapter()
{
(pX->*mf)();
}
Oto jak można go używać:
#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>);
}
Wreszcie ją e to live example.
Czy otrzymujesz błąd. Jaki to błąd? – 0x499602D2
Używam kompilatora Visual Studio 2012. Wstawię błąd kompilatora do mojego pytania. –
Niestety, błąd kompilatora na początku, teraz jego prawa –