1

I'm using Visual Studio 2015 and I would like to append Button::track_ function to the callbacks vector so that all functions inside callbacks will be called once the invoke_all function in events class was called.

buttons.h

class Button:
    public Texture
{
public:
    void track();
}

buttons.cpp

void Button::track()
{
    Events::add_handler(&Button::track_);
}

void Button::track_() { ... }

events.h

typedef std::function<void()> cb;
extern std::vector<cb> callbacks;

class Events
{
public:
    static void add_handler(cb);
    static void invoke_all();
};

events.cpp

std::vector<cb> callbacks;

void Events::add_handler(cb c)
{
    callbacks.push_back(c);
}

void Events::invoke_all()
{
    decltype(callbacks.size()) i = 0;
    for (; i < callbacks.size(); i++)
        callbacks[i]();
}

I always get this error message

Error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)' SDL d:\programs\microsoft visual studio 2015\vc\include\type_traits 1494

Xtravagant
  • 121
  • 8
  • 1
    Which line triggers the error? Is it inside `Events::invoke_all`? What is its code? Please, create [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – Daniel Langr Apr 20 '18 at 07:54

1 Answers1

1

You can't call a non-static member function pointer without an instance of the class to call it on. I'm guessing you want to capture an instance of Button in the std::function function object. One way of doing this is using a lambda:

void Button::track()
{
    Events::add_handler([this]{track_();});
}

By capturing this in the lambda you can then implicitly call member functions on that instance within the body of the lambda.

Of course you need to guarantee that the Button instance is alive when the callback is called.

Chris Drew
  • 14,926
  • 3
  • 34
  • 54
  • Can you explain what's this thingy `[this]{track_();}` does because I'm only a newbie. I know how to instantiate a class, but in that case it's beyond my experience. – Xtravagant Apr 20 '18 at 08:02
  • 1
    @Xtravagant It is a [lambda expression](http://en.cppreference.com/w/cpp/language/lambda); sometimes called lambda functions, anonymous functions, closures, or similar. – zenzelezz Apr 20 '18 at 08:11
  • Do I still have to do that even if I specify `Button::track()` as static or shared? – Xtravagant Apr 20 '18 at 08:17
  • @Xtravagant As I say, if `Button::track()` is static then you don't need an instance of `Button` to call it and you should be able to pass the function pointer directly. I've added a link explaining what a lambda is. – Chris Drew Apr 20 '18 at 08:41