2012-02-16 108 views
3

我有一個情況非常類似於此:傳遞函數指針到模板

#include <iostream> 

template<class B> 
class A 
{ 
public: 
    A<B>(const B& b) : m_b(b) {} 
    void foo() 
    { 
     m_b(*this); 
    } 
private: 
    B m_b; 
}; 

class B 
{ 
public: 
    template<class C> 
    void operator()(const C& c) 
    { 
     std::cout << "Bar!\n"; 
    } 
}; 


int main() 
{ 
    B b;   
    A<B> a(b); 
    a.foo(); 

    return 0; 
} 

然後,我決定用一個函數指針,而不是函數對象B,即我想要做這樣的事情:

#include <iostream> 

template<class B> 
class A 
{ 
public: 
    A<B>(const B& b) : m_b(b) {} 
    void foo() 
    { 
     m_b(*this); 
    } 
private: 
    B m_b; 
}; 

template<class C> 
void bar(const C& c) 
{ 
std::cout << "Bar!\n"; 
} 

int main() 
{ 
    typedef void (*barPointer)(const A<barPointer>& a); // <--  
    A<barPointer> a(&bar); 
    a.foo(); 

    return 0; 
} 

這顯然不會編譯(注意在<圓 - )。我的問題是:如何去做這件事?

+0

最簡單的解決方案是返回到一個函數對象;這也可以具有性能優點,因爲內聯更容易。你有一個特別的理由想要一個函數指針嗎? – 2012-02-16 17:45:34

+0

函數對象如何更容易內聯?一個功能很容易內聯,如果它的身體是可見的。這適用於成員函數以及免費函數。 – wilhelmtell 2012-02-16 17:49:01

+0

@wilhelmtell:成員函數在編譯時由模板參數指定,因此可以很容易地進行內聯。函數指針的目標在運行時由構造函數參數指定;編譯器可能無法告訴它是什麼,即使可以,也可能不會內聯它。 – 2012-02-16 17:51:23

回答

0

我認爲要問的關鍵問題是您的barPointer類型是什麼?它是一個指向函數的指針,但正如您試圖定義它的那樣,您已經創建了一個無限遞歸定義。要結束遞歸,你必須考慮這個指針類型的「根」或「基本情況」是什麼。既然你知道A實例的類型,你將會傳遞給你的函數,那麼你真的在尋找一個「佔位符」類型,它允許模板在沒有圓形的情況下被實例化。這可能是一個非常「通用」的函數指針類型,如void(*)(void*),或者它可能是更具體的東西,但無論如何,我相信它需要是一個函數指針類型,不包括A的定義,但可以是作爲參數傳遞了一個A<>實例。最通用的形式是void(*)(void*),但您可以始終定義某種類型的多態基類以提高類型安全性。

這裏,例如,將是最通用的情況的一個例子:

typedef void (*generic_t)(void*); 

template<typename T> 
struct A 
{ 
     A(const T& t): func_ptr(t) {} 
     void foo() { func_ptr(this); } 
     T func_ptr; 
}; 

void func(void* arg) 
{ 
     const A<generic_t>* a = reinterpret_cast<const A<generic_t>*>(arg); 
} 

int main() 
{ 
     A<generic_t> a(&func); 
     a.foo(); 
     return 0; 
} 

雖然這看起來很危險,這不是真的,如果你認爲你的basePointer例子中,你已經知道類型的事實你要傳遞給你的basePointer函數指針的對象。如果你想要更多的類型安全來防止無意的錯誤,你總是可以創建一些類型的抽象基類,A繼承自。我說「抽象的基類」,因爲這將允許您使用傳遞給該函數的指針,而不顯式轉換爲它的派生類型。然後,您的「通用佔位符」功能-ptr類型可能類似void(*)(const Base&)而不是非類型安全的void(*)(void*)