Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functions as template parameters issue

Tags:

c++

templates

I have this problem bothering me. I have the FSM class which associate keys to callbacks

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

And some callbacks classes

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

Now if into the main I do:

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

The first call is fine, in the second one compiler complains:

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’

Also notice that the following is fine

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

Any idea? Thanks in advance for your help.

Simone

like image 916
Simone Avatar asked Oct 08 '11 10:10

Simone


People also ask

Can a template parameter be a function?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

What is correct for template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Why do we use template template parameter?

Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

How do you call a function in a template?

Defining a Function TemplateA function template starts with the keyword template followed by template parameter(s) inside <> which is followed by the function definition. In the above code, T is a template argument that accepts different data types ( int , float , etc.), and typename is a keyword.


1 Answers

You haven't defined Callback::operator(). There is no secound function for Callback just the function from CallbackBase which takes a CallbackBase and a int as parameters! This is why the compiler moans about "unresolved overloaded function type".

The type of the inherited function is bool (CallbackBase::*operator())(int). This function can be automatically converted to a bool (Callback::*operator())(int) because you can always apply a Callback to a function that accepts only a CallbackBase. This is the reason why the following works - it's a automatic cast happening there.

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

The problem happens with the template type deduction:

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

This doesn't work since the types that given via Callback_t and the type required by the function pointer do not match when instanciating the callback function. You can resolve the problem with a explicit cast of the function pointer to (Callback::*operator())(int) before the type deduction takes place. If you change the callback function to the following you do not require the two types to be identical and it compiles without the cast.

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

What I don't understand is why you add the virtual function. Wouldn't the following do the same, be more simple and readable and even faster (no virtual function call)? The doCall function would be required to be public.

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

Another improvement would be to make the callback function static. It would be even more simple if the doCall functions would be static - this would make the callback function obsolete and would avoid creating a temporary to call doCall.

like image 150
David Feurle Avatar answered Sep 22 '22 14:09

David Feurle