Функции как выдача параметров шаблона - PullRequest
7 голосов
/ 08 октября 2011

Меня эта проблема беспокоит. У меня есть класс FSM, который связывает ключи с обратными вызовами

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

И некоторые классы обратных вызовов

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

Теперь, если в основной я делаю:

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

Первый вызов в порядке, во втором компилятор жалуется:

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’

Также обратите внимание, что все в порядке

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

Есть идеи? Заранее благодарим за помощь.

Simone

1 Ответ

2 голосов
/ 09 октября 2011

Вы не определили Callback :: operator (). Для Callback нет функции secound, только функция из CallbackBase, которая принимает CallbackBase и int в качестве параметров! Вот почему компилятор стонет о «неразрешенном типе перегруженной функции».

Тип унаследованной функции - bool (CallbackBase :: * operator ()) (int). Эта функция может быть автоматически преобразована в bool (Callback :: * operator ()) (int), потому что вы всегда можете применить Callback к функции, которая принимает только CallbackBase. Это причина того, что следующие работы - это автоматическое приведение там.

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

Проблема возникает с удержанием типа шаблона:

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

Это не работает, поскольку типы, которые передаются через Callback_t, и тип, требуемый указателем функции, не совпадают при создании экземпляра функции обратного вызова. Вы можете решить проблему с помощью явного приведения указателя на функцию (Callback :: * operator ()) (int) до того, как произойдет вывод типа. Если вы измените функцию обратного вызова на следующую, вам не нужно, чтобы два типа были идентичными, и она компилируется без преобразования.

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

Чего я не понимаю, так это почему вы добавляете виртуальную функцию. Разве следующее не сделает то же самое, будет более простым, читаемым и даже более быстрым (без вызова виртуальной функции)? Функция doCall должна быть общедоступной.

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

Еще одним улучшением было бы сделать функцию обратного вызова статической. Было бы еще проще, если бы функции doCall были статическими - это сделало бы функцию обратного вызова устаревшей и позволило бы избежать создания временного элемента для вызова doCall.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...