C++ std::bind accept typename as first argument

346 views Asked by At

I have encountered some strange behavior.

This code gives me errors:

struct Game {
    void stop() {std::cout << "success\n";}
};

template<class ...Args>
struct holder {
    std::map<std::string, std::function<void(Args...)>> funcMap;

    template <typename T, typename U>
    void connect(T* targObj, const std::string& funcName) {
        std::function<void(Args...)> newFunc = std::bind(U, targObj); 
        //expected primary expression before ',' token on line above
        funcMap[funcName] = newFunc;
    }

    void invoke(const std::string& funcName, class Args...Vals) 
    {funcMap[funcName](Vals...);}
};

int main() {
    holder<> h;
    Game g;
    h.connect<Game, &Game::stop>(g, "close");
    h.invoke();
}

It seems that std::bind does not like typenames as inputs. Is there a workaround for this? It works fine to manually use std::bind with the same parameters, but it is more boilerplate code:

std::function<void(Args...)> newFunc = std::bind(&ae::Game::stop, targObj);

Even without any input, it still errors on compile. Why doesn't my function work?

EDIT: Thanks for the help. As it turns out, bind does not accept a typename, it accepts an address.

3

There are 3 answers

2
dzada On

I guess the function is static ? If not you have the solution, it needs an object to be called.

But bind is trying to call g with argument "close"on no object, can t work if not static

1
Astrognome On

For anyone trying to accomplish this:

Just use macros. This is close to impossible without a custom bind implementation.

#define BINDMF(a,b,c) (std::bind(&a::b, c))
0
Mooing Duck On

It's pretty straightforward really:

template <typename T, typename U>
void connect(T* targObj, const std::string& funcName) {

T and U must be types, since they are type templates. This function is a little awkward that it forces one to write both template parameters.

h.connect<Game, &Game::stop>(g, "close");

T=Game, and Game is a type, so that's good. U=&Game::stop, which is a variable/instance of void (Game::*)(), so that's the cause of your failure. I don't know why your compiler is giving silly errors. The solution is to pass the function variable as a parameter:

template <typename T>
void connect(T* targObj, void(Game::func*)(Args...), const std::string& funcName) 

and calling it as:

h.connect(g, &Game::stop, "close");

As shown here: http://coliru.stacked-crooked.com/a/895584175a1a6a61