Home > front end >  bind with enable_if'd member functions
bind with enable_if'd member functions

Time:11-10

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

  • Related