I'm getting tripped up on calling bind on an enable_if'd member function. I've worked around it using if constexpr, but I'm curious what the solution would be for this issue. The code is the simplest reproducer and not representative of the overarching problem I'm trying to solve. How can I make this work?
#include <iostream>
#include <type_traits>
#include <functional>
template <typename T>
class test {
public:
template <typename U = T>
typename std::enable_if<std::is_copy_constructible<U>::value, void>::type
foo(const T& v){
std::cout << "copy constructible";
}
template <typename U = T>
typename std::enable_if<!std::is_copy_constructible<U>::value, void>::type
foo(const T& v){
std::cout << "not copy constructible";
}
void foo_bar(const T& v){
std::cout << "test";
}
};
int main(int argn, char** argc){
test<int> myfoo;
myfoo.foo(3); //Works
auto func = std::bind(&test<int>::foo_bar, &myfoo, 3); //Works
auto func = std::bind(&test<int>::foo, &myfoo, 3); //Doesn't work
func();
return 0;
}
CodePudding user response:
The problem is that U is substituted only when the member function template foo is actually called, and not when it is used inside of std::bind(). This means that when specifying &test<int>::foo inside bind(), it isn't known which of the two member function templates is going to be actually instantiated since the instantiation of definition will happen when we actually call foo(), and so the compiler can't decide which of them you're referring to. This is exactly what <unresolved overloaded function type> means in the error that you're getting:
no matching function for call to 'bind(<unresolved overloaded function type>, test<int>*, int)'
32 | auto func2 = std::bind(&test<int>::foo, &myfoo, 3); //Doesn't work
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can solve this by either specifying U explicitly, like:
&test<int>::foo<int>
or by using a lambda, like:
auto func = [&myfoo]() { myfoo.foo(3); };
