Home > Back-end >  Why am I getting "error: no match for ‘operator->*’" when the parameters on both sides
Why am I getting "error: no match for ‘operator->*’" when the parameters on both sides

Time:09-26

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 foroperator->*’ (operand types are ‘std::shared_ptr<main()::foo>’ andbool (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.

  • Related