【问题标题】:bind with enable_if'd member functions与 enable_if\'d 成员函数绑定
【发布时间】:2022-11-11 02:27:38
【问题描述】:

我在 enable_if'd 成员函数上调用 bind 时被绊倒了。我已经使用if constexpr 解决了这个问题,但我很好奇这个问题的解决方案是什么。该代码是最简单的复制器,并不代表我要解决的总体问题。我怎样才能使这项工作?

#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;                                                                                                                                                                                                                                                     

}                                                                                                                                                                                                                                                               

【问题讨论】:

  • 为什么不使用 use lambda 代替:auto func = [&amp;myfoo]() { myfoo.foo(3); }
  • 这是一个非常简化的低级库示例。绑定在代码中,我只有很小的控制权

标签: c++ metaprogramming sfinae


【解决方案1】:

问题是U 仅在实际调用成员函数模板foo 时被替换,而不是在std::bind() 内部使用时被替换。这意味着当在bind() 中指定&amp;test&lt;int&gt;::foo 时,不知道两个成员函数模板中的哪一个将被实际实例化,因为定义的实例化将在我们实际调用foo() 时发生,因此编译器无法确定您指的是哪一个。这正是 &lt;unresolved overloaded function type&gt; 在您收到的错误中的含义:

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
      |                ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~

您可以通过明确指定 U 来解决此问题,例如:

&amp;test&lt;int&gt;::foo&lt;int&gt;

或通过使用拉姆达, 喜欢:

auto func = [&amp;myfoo]() { myfoo.foo(3); };


在 C++20 中有第三种方法可以使用requires-clause 解决这个问题,如下所示。请注意,以下程序格式正确,但 gcc 和 msvc 错误地拒绝了它。只有 clang 接受它,这是正确的行为。 Demo

#include <iostream>
#include <type_traits>                                                                                                                                                                                                                                            
#include <functional>                                                                                                                                                                                                                                       

template <typename T>                                                                                                                                                                                                                                           
class test {                                                                                                                                                                                                                                                    
public:                                                                                                                                                                                                                                                         

                                                                                                                                                                                                                                                                                                                                                                                                                         
  void foo(const T& v) requires std::is_copy_constructible_v<T>{
      std::cout << "copy constructible";
  }                                                                                                                                                                                                                                              
  void foo(const T& v) requires (!std::is_copy_constructible_v<T>) {
      std::cout << "non 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 func2 = std::bind(&test<int>::foo, &myfoo, 3); //works                                                                                                                                                                                           

  func(); 
  func2();                                                                                                                                                                                                                                                      

}  

【讨论】:

  • 感谢您的解释。我不控制绑定代码,所以 lambda 会被淘汰,尽管建议的修复是我可以改变的
  • @Steve 你能用 C++20 吗?如果是,那么我有另一个解决方案并且可以添加它。别客气 :)
  • 很想看到替代品。我确实可以访问 c++20
  • @Steve 我在 C++20 中使用 requires-clause 添加了第三种解决方法。见working demo。请注意,目前只有 clang 接受正确行为的程序。而 gcc 和 msvc 拒绝该程序,因此它们有错误。我已经提交了这两个错误(gcc 和 msvc,因为它们错误地拒绝了该程序)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-14
相关资源
最近更新 更多