I'm trying to call a function from within a template function inside a template.
The call itself, however, doesn't compile, instead I get the following error:
/home/alexis/tmp/b.cpp: In instantiation of ‘bool callback_manager<C>::call_member(F, ARGS ...) [with F = bool (main()::foo::*)(int, int, int); ARGS = {int, int, int}; C = std::vector<std::shared_ptr<main()::foo> >]’:
/home/alexis/tmp/b.cpp:43:47: required from here
/home/alexis/tmp/b.cpp:15:19: error: no match for ‘operator->*’ (operand types are ‘std::shared_ptr<main()::foo>’ and ‘bool (main()::foo::*)(int, int, int)’)
if(!(c->*func)(&args...))
~~^~~~~~~~
Here is a simplified version of the code I'm trying to compile:
#include <memory>
#include <vector>
template<typename C>
class callback_manager
{
public:
template<typename F, typename ... ARGS>
bool call_member(F func, ARGS ... args)
{
C callbacks(f_callbacks);
for(auto c : callbacks)
{
if(!(c->*func)(args...))
{
return false;
}
}
return true;
}
private:
C f_callbacks;
};
int main()
{
class foo
{
public:
typedef std::shared_ptr<foo> pointer_t;
typedef std::vector<pointer_t> vector_t;
bool the_callback(int, int, int)
{
return true;
}
};
callback_manager<foo::vector_t> m;
m.call_member(&foo::the_callback, 5, 13, 7);
return 1;
}
Looking at the parameters, it seems to be that both are correct:
std::shared_ptr<main()::foo>
and
bool (main()::foo::*)(int, int, int)
CodePudding user response:
The fact is that the ->*
operator doesn't work with the std::shared_ptr<>
.
The solution is to retrieve the bare pointer like so:
if(!(c.get()->*func)(args...)) ...
It then compiles as expected.
You can also rewrite it as follow, which I think is more cryptic:
if(!(*c).*func)(args...)) ...
(i.e. the shared_ptr::operator * ()
function, like the shared_ptr::get()
function, returns the bare pointer held by the shared pointer.)
CodePudding user response:
Replace
if(!(c->*func)(args...))
with
if(!(std::cref(func)(c, args...)))
to use the INVOKE machinery of C . Or use std::invoke
directly.
INVOKE concept in the standard, and std::invoke
, where designed to work with pmfs and smart pointers.
Meanwhile, ->*
isn't overloaded by smart pointers. So direct use like that won't work.
As a side benefit, now a non member function can be passed in as the func.