2011-10-08 24 views
7

Bu sıkıntı beni rahatsız ediyor. Ben FSM sınıf var ki geri aramalarıŞablon parametresi olarak işlevler sorunu

class FSM 
{ 
public: 

typedef bool (FSM::*InCallback_t)(int); 
typedef std::map< std::string, InCallback_t > Table; 

// Since I would like to allow the user to register both functors and class member functions 
template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) > 
bool callback(int x) 
{ 
    return (Callback_t().*CallbackFunct_t)(x); 
} 

void addCallback(const std::string& iKey, InCallback_t iCallback) 
{ 
    _table.insert(std::make_pair(iKey, iCallback)); 
} 

    [ ... ] 

private: 
    Table _table; 
}; 

için ortak anahtarları Ve bazı geri aramaları sınıflar

class CallbackBase 
{ 
public: 

    bool operator()(int x){ return doCall(x); } 

private: 
    virtual bool doCall(int x){ return true; } 
}; 


class Callback: public CallbackBase 
{ 
private: 
    bool doCall(int x) 
    { 
     std::cout << "Callback\n"; 
     return true; 
    } 
}; 

Şimdi ana içine Yaparsam:

FSM aFSM; 
// OK 
aFSM.addCallback("one", &FSM::callback< CallbackBase, &CallbackBase::operator() >); 
// KO 
aFSM.addCallback("two", &FSM::callback< Callback, &Callback::operator() >); 

ilk çağrı, gayet ikinci bir derleyici şikayetçi:

Test.cpp: In function ‘int main(int, char**)’: 
Test.cpp:104:77: error: no matching function for call to ‘FSM::addCallback(const char [4], <unresolved overloaded function type>)’ 
Test.cpp:104:77: note: candidate is: 
Test.cpp:24:7: note: void FSM::addCallback(const string&, FSM::InCallback_t) 
Test.cpp:24:7: note: no known conversion for argument 2 from ‘<unresolved overloaded function type>’ to ‘FSM::InCallback_t’ 

Ayrıca şu

typedef bool (Callback::*Function_t)(int); 
Function_t aFunction = &Callback::operator(); 
(Callback().*aFunction)(5); 

herhangi bir fikir ince olduğunu fark? Yardımlarınız için şimdiden teşekkür ederiz.

Simone

+2

Derleyici bir hata gibi görünüyor. : | – Nawaz

+0

Evet, ben de gerekiyordu. Oldukça garip olan – Simone

+0

Ben de türetilmiş sınıfın bir üye-işaretçisi ile taban sınıfı işlevleri (veya operatörleri) kullanarak, bununla bazı sorunlar vardı. MSVC'de en azından şablonlarda çalışmaz. – Xeo

cevap

2

Sen Geri arama :: operatörü tanımlamadınız(). CallbackBase işlevinden bir CallbackBase işlevini ve bir int parametresini alan bir geri arama işlevi yoktur! Bu yüzden derleyici, "çözümlenmemiş aşırı yüklenmiş işlev türü" konusunda inandırıcıdır.

Devralınan işlev türü bool'dur (CallbackBase :: * operator()) (int). Bu işlev otomatik olarak bir boole (Geri Arama :: operatör()) (int) dönüştürülebilir, çünkü her zaman bir Geri Arama Düzeni kabul eden bir işleve bir Geri Çağırma uygulayabilirsiniz. Aşağıdaki çalışmaların nedeni budur - oradaki bir otomatik dökümdür. geri arama instanciating zaman

template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) > 
with: Callback_t = Callback, CallbackFunct_t = bool (CallbackBase::*CallbackFunct_t)(int) 

Bu Callback_t ve fonksiyon pointer gerektirdiği türü yoluyla verilen türleri beri çalışmıyor eşleşmiyor:

typedef bool (Callback::*Function_t)(int); 
Function_t aFunction = &Callback::operator(); 

sorun şablon türü kesinti ile olur işlevi. Sorunu, tür işareti indirilmeden önce işlev işaretçisinin açık bir dizesiyle (Geri arama :: * operatör()) (int) olarak çözebilirsiniz. Geri arama işlevini aşağıdaki şekilde değiştirirseniz, iki türün aynı olmasını ve döküm olmadan derlemesini gerektirmezsiniz.

template< typename Callback_t> 
bool callback(int x) 
{ 
    return Callback_t()(x); 
} 

Anlamadığım şey, sanal işlevi neden eklediğinizdir. Aşağıdakiler aynı şeyi yapmaz, daha basit ve okunabilir ve hatta daha hızlı (sanal işlev çağrısı) olmaz mı? DoCall işlevinin herkese açık olması gerekir.

Geri arama işlevini statik yapmak için başka bir iyileştirme yapılması gerekir. DoCall fonksiyonları statik olacaksa daha da basit olur - bu geri çağırma fonksiyonunun eski olmasını sağlar ve doCall çağrısı yapmak için geçici bir durum yaratmasını engeller.

+0

Cevabınız için teşekkür ederiz. Bazı yorumlar. Callback :: operator() mevcut ise nokta hakkında. Temel sınıftan miras alınıyor ve gerçekte sorduğum kodun son üç satırı düzgün çalışıyor. Gerçekten de bana daha çok derleyici bir böcekmiş gibi geliyor. Evet, fonksiyon parametresini şablon parametresi olarak kaldırabildiğim doğrudur, ancak bu durumda sadece functor nesnesini kullanabilmekteydim. Gerçekten de daha esnek olmayı isterdim. Tüm geri çağrıları üye işlevleri olarak uygulayan sınıf. ... – Simone

+0

.. Neden operatör() ve sanal doCall tanımladım. Bu şablon yöntemi denen bir model. Evet, yukarıdaki örnekte işe yaramıyor, ancak Operatörde() CallbackBase'e, her türetilmiş sınıfta uygulanan geri çağırma işlevinin çağrılmasından önce ve sonra gerçekleştirilen bazı ön operasyonlar ve post-operasyonlar gerçekleştirildiğini hayal edebilirsiniz. Örnek, doCall'ın yürütme süresi hakkında istatistik almak olabilir. – Simone

+0

@simone Derleyici bir hataya inanmıyorum. Kodunuzu gcc ve görsel stilde aynı sonuçla derlemeye çalıştım. Visual Studio'da hata iletisi: 'bool (__thiscall CallbackBase :: *) (int)' için 'bool (__thiscall Callback :: * const) (int)' dönüştürebilirsiniz. Callback :: operator() işlevi yoktur, sadece temel sınıftan birini çağırır. Aşağıda belirtilen derleyicilerden hiçbiri derlenmez: typedef void (Geri arama :: * func) (int); func f = & Geri arama :: operator(); –

İlgili konular