1

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.

Astrognome
  • 303
  • 3
  • 9
  • Show the compiler error, and use `auto` instead of `std::function ` – dzada Sep 03 '13 at 22:12
  • error is in the comment next to the offending line of code. I was using auto, but I just tried this. – Astrognome Sep 03 '13 at 22:14
  • is `ae::Game::stop` a type or a variable or a function? – Mooing Duck Sep 03 '13 at 22:15
  • @Astrognome: Tip: An instance of a function is not a type. – Mooing Duck Sep 03 '13 at 22:16
  • What would I use then instead of typename? The error comes from bind not accepting a template typename as an arg. – Astrognome Sep 03 '13 at 22:17
  • @Astrognome: The type of the `ae::Game::stop` function presumably. Since we don't know the types of... anything in your code, and your code makes no sense at all, we can't really help you a whole lot. – Mooing Duck Sep 03 '13 at 22:17
  • Bind has to accept a function type, like &Class::memberFunc – Astrognome Sep 03 '13 at 22:19
  • @Astrognome: Bind accepts a _function_, not a function _type_. `template` accepts a function _type_, not a function. And [the code you posted doesn't give the errors you describe](http://coliru.stacked-crooked.com/a/72bcd8cb8699c5c1). The triple edit _DOES NOT WORK FINE_. `ARGS` is never defined. – Mooing Duck Sep 03 '13 at 22:23
  • Actually, now that I look at your code, what you're trying to do is nearly impossible. You cannot trivially store functions with different signatures in the same map, even with the magic that is std::function. See [this question](http://stackoverflow.com/q/8304582/845092) – Mooing Duck Sep 03 '13 at 22:25
  • I think I'll probably just use macros. It'll probably be easier, and accomplish the same purpose with less complexity. The args... are defined elsewhere in the class. Also, the functions all have the same signature. – Astrognome Sep 03 '13 at 22:26
  • @Astrognome While using a macro to get it to work now, because you have to, might be needed in the real world, if you plan to code with C++, definitely go to the effort of learning how to do it properly. Also learn to ask things at SO, such as *edit the question to include the error*! Also, read http://sscce.org – hyde Sep 04 '13 at 07:15
  • It does include the error. I put it in the comment next to the offending line. – Astrognome Sep 04 '13 at 12:58

3 Answers3

0

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

dzada
  • 5,344
  • 5
  • 29
  • 37
  • I just need bind to accept typename. If I just directly put in the type like this: std::function newFunc = std::bind(&ae::Game::stop, targObj); then it works fine. – Astrognome Sep 03 '13 at 22:22
  • 1
    yes because this `&ae::Game::stop` is an address, this `typename &ae::Game::stop `means nothing. – dzada Sep 03 '13 at 22:25
0

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

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
-1

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))
Astrognome
  • 303
  • 3
  • 9
  • [oh, this?](http://coliru.stacked-crooked.com/a/51573005394f3118). Simply changing the bits to code that makes sense makes this easy. – Mooing Duck Sep 03 '13 at 22:45