2013-03-24 20 views
6

Próbuję użyć funkcji klasy (przerwanie rutynowe usługi),Klasa wskaźnik funkcji członka

void (ClassName::*fp)(void)=ClassName::FunctionName; 

i dołączenie go do Arduino przerwać pin za pomocą funkcji z następującymi wejściami typu, ale to nie praca.

void attachInterrupt(int, void (*)(void),int); 

Jak mogę to zrobić? Procedura obsługi przerwania (ISR) musi uzyskać dostęp do danych obiektu prywatnego, więc nie mogę utworzyć funkcji poza klasą.

Mój błąd kompilatora:

Uwaga: szukam rozwiązania wewnątrz klasy i zaakceptuje odpowiedź, że pokazuje mi rozwiązanie lub pokazuje mi, że to nie jest możliwe.

+2

Czy otrzymujesz błąd. Jaki to błąd? – 0x499602D2

+0

Używam kompilatora Visual Studio 2012. Wstawię błąd kompilatora do mojego pytania. –

+0

Niestety, błąd kompilatora na początku, teraz jego prawa –

Odpowiedz

6

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.

+0

dziękuję, bardzo pouczająca odpowiedź. –

+0

@FlyingSwissman: Cieszę się, że mogę pomóc –

2

Każda funkcja członkowska klasy ma niejawny pierwszy parametr, którym jest wskaźnik this, więc twoja metoda nie jest z listą parametrów pustych - przyjmuje jeden parametr - instancję, do której jest wywoływana.

+0

OK, dzięki temu ma sens, ale nie rozwiązuje mojego problemu. Czy mogę tylko upublicznić dane obiektu i stworzyć ISR poza obiektem? czy jest jakieś dzieło? –

+0

@AndyProwl dobry punkt. Dziękujemy –

+1

@FlyingSwissman: Proponuję obejście w mojej odpowiedzi. Niestety, niewiele można zrobić, gdy funkcja akceptuje surowy wskaźnik funkcji. –

0

Można użyć boost::function<> lub boost::bind<> pkt do funkcji składowej klasy:

# include <boost/function.hpp> 
# include <boost/bind.hpp> 
class FunctionClass { 
    private: 
     double a_; 
    public: 
     FunctionClass (const double & a): a_(a){} 
     double multWithA (const double & x) const { return a_*x;} 
     double operator()(const double & x) const { return a_*x;} 
}; 

FunctionClass myClass (2.0); 
double x = 12.0; 
boost :: function <double (FunctionClass *, double)> funcPtr , funcPtr1; 
funcPtr =& FunctionClass :: multWithA; 
funcPtr1 =& FunctionClass :: operator(); 

std :: cout << myClass . multWithA (x) << std :: endl; 
std :: cout << funcPtr (& myClass ,x) << std :: endl; 
std :: cout << funcPtr1 (& myClass ,x) << std :: endl; 

// Bind the function with the class instance 
boost :: function <double (double)> funcPtrNew ; 
funcPtrNew = boost :: bind (funcPtr ,& myClass ,_1); 
std :: cout << funcPtrNew (x) << std :: endl; 
+2

Nie może, musi przekazać wskaźnik funkcji "void (*) (void)". (Nie jestem wielkim fanem biblioteki arduino.) – ipc

+0

@ipc powinien również działać z pustką, dlaczego nie? – 4pie0

+1

Ponieważ musi zadzwonić [void attachInterrupt (int, void (*) (void), int)] (http://arduino.cc/en/Reference/AttachInterrupt). – ipc

Powiązane problemy