2

EDIT3: If I delete the second createTriangle function, it works. So how can I bind overloaded functions?

I have a function which takes a function object with one parameter, like this:

int createObject(std::function<void(int)>);

How can I call this function with std::bind? I tried it like this:

createObject(std::bind(&ClassA::createTriangle, std::placeholders::_1, a, b, c, color));

But this gives me an error:

candidate template ignored: couldn't infer template argument

ClassA::createTriangle is a static function.


Additional info:

void ClassA::createTriangle(int id, const glm::vec3 & a, const glm::vec3 & b, const glm::vec3 & c, const glm::vec3 & col) {
    /* ... */
}

int ClassB::createTriangle(const glm::vec3 & a, const glm::vec3 & b, const glm::vec3 & c, const glm::vec3 & color) {
    return classCInstance.createObject(std::bind(&classA::createTriangle, std::placeholders::_1, a, b, c, color));
}

int ClassC::createObject(std::function<void(int)> f) {
    f(++id);
    return id;
}

There is another static createTriangle function in ClassA, with a different last parameter. Is that maybe a problem? Does bind not know which createTriangle to choose? It looks like this:

void ClassA::createTriangle(int id, const glm::vec3 & a, const glm::vec3 & b, const glm::vec3 & c, const std::initializer_list<glm::vec3> & colors) {
    /* ... */
}
gartenriese
  • 4,131
  • 6
  • 36
  • 60

1 Answers1

7

ClassA::createTriangle is an overloaded function, you cannot use it without specifying which overload you intend to use. std::bind has to return a generic wrapper, it cannot figure it by itself, you have to specify.

This should work:

void (*mySpecificCreateTriangle)(int, const const glm::vec3 &, const const glm::vec3 &, const const glm::vec3 &, const const glm::vec3 &) = &createTriangle;
createObject(std::bind(mySpecificCreateTriangle, std::placeholders::_1, a, b, c, color));

Since you are using C++11, you will be happier with a lambda:

createObject([=](int id){ return createTriangle(id, a, b, c, color); });
Juliano
  • 39,173
  • 13
  • 67
  • 73
  • Are you sure std::function will take a lambda? – thor Mar 09 '14 at 17:08
  • @TingL: Yes, the whole purpose of std::function is to wrap any callable object, including a lambda. – Juliano Mar 09 '14 at 17:10
  • @gartenriese Last time I checked, if you have `int createObject(std::function); ` and call it with a lambda `createObject([=](int id){ return createTriangle(id, a, b, c, color); });`, there will be compile error in gcc. – thor Mar 09 '14 at 17:11
  • @Ting L: I use clang, so maybe you're right about gcc. – gartenriese Mar 09 '14 at 17:12
  • Oh, do you mean because of the return? I don't use a return, Juliano must have added it by accident. – gartenriese Mar 09 '14 at 17:13
  • @TingL: It is probably a bug in you version of GCC. It works for me in both GCC and CLANG, and on ideone too: https://ideone.com/80ySfX – Juliano Mar 09 '14 at 17:15
  • @gartenriese No, it's not about the return. I think a lambda is not considered a `std::function` object, and at least gcc does not take care of the implicit conversion from lambda to the corresponding `std::function` object. – thor Mar 09 '14 at 17:16
  • It is okay to return the result of a void function, the return type of the lambda will also be void. – Juliano Mar 09 '14 at 17:16
  • @Juliano Your code works for my version of gcc as well. Maybe it will not work when the function is a template. For example, https://ideone.com/IBUCyX – thor Mar 09 '14 at 17:24
  • @TingL: The problem is that you are trying to infer the arguments of two nested templates at the same time (the std::function<> constructor and the map<> function), and C++ doesn't know how to do that. This is the fixed version of your example: https://ideone.com/vlqeL0 – Juliano Mar 09 '14 at 17:33
  • @Juliano Yes. That is what I was referring to. Have to assign to a `std::function` object first, and cannot directly use it when templates are involved. – thor Mar 09 '14 at 18:33
  • If the `createObject` function here were templated, then a lambda has to be assigned to a std::function first before it can be used. – thor Mar 09 '14 at 18:39