2013-03-24 215 views
6

我試圖使用類功能(中斷服務例程),類成員函數指針

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

並將其附加到一個Arduino中斷引腳使用具有以下類型輸入的功能,但其不工作。

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

我該如何做到這一點?中斷服務例程(ISR)需要訪問privat對象數據,所以我不能在類之外創建一個函數。

我的編譯器錯誤:

注:我在尋找類中的解決方案,將接受表明我一個解決方案或顯示我這是不可能的答案。

+2

你得到一個錯誤。它有什麼錯誤? – 0x499602D2 2013-03-24 14:30:01

+0

我正在使用Visual Studio 2012編譯器。我會把編譯器錯誤置於我的問題中。 – 2013-03-24 14:31:36

+0

抱歉,錯誤的編譯器錯誤一開始,現在它的權利 – 2013-03-24 14:41:34

回答

6

如果該函數不是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()會的工作,因爲結果是無法轉換爲一個函數指針。 Lambdas可以轉換爲函數指針,但前提是它們不捕獲(而且這裏的lambda需要捕獲該對象來調用成員函數)。

因此,唯一的(醜陋的)解決方法是具有全局適配器函數,該函數在通過全局指針變量可用的對象上調用成員函數。

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>); 
} 

,她e是live example

+0

謝謝,非常翔實的答案。 – 2013-03-24 14:58:45

+0

@FlyingSwissman:很高興能幫到 – 2013-03-24 14:59:33

2

每個類成員函數都有一個隱含的第一個參數,即this指針,因此您的方法實際上並不包含void paramter list - 它只接受一個參數 - 它被調用的實例。

+0

好的,謝謝,這是有道理的,但不能解決我的問題。我能做的唯一事情就是公開對象數據並在對象之外創建一個ISR?還是有工作? – 2013-03-24 14:39:08

+0

@AndyProwl好點。謝謝 – 2013-03-24 14:49:20

+1

@FlyingSwissman:我在回答中提出了一個解決方法。不幸的是,當一個函數接受一個原始函數指針時,可以做的事情並不多。 – 2013-03-24 14:51:14

0

您可以使用boost::function<>boost::bind<>指向一個類的成員函數:

# 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

他不能,他必須傳遞一個void(*)(void)函數指針。 (我不是arduino庫的忠實粉絲。) – ipc 2013-03-24 14:36:41

+0

@ipc也應該與void一起工作,爲什麼不呢? – 4pie0 2013-03-24 14:41:45

+1

因爲他必須調用[void attachInterrupt(int,void(*)(void),int)](http://arduino.cc/en/Reference/AttachInterrupt)。 – ipc 2013-03-24 14:46:03