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); };