【问题标题】:How to directly bind a member function to an std::function in Visual Studio 11?如何在 Visual Studio 11 中将成员函数直接绑定到 std::function?
【发布时间】:2013-06-12 11:27:05
【问题描述】:

我可以轻松地将成员函数绑定到 std::function,方法是使用带有捕获子句的 lambda 表达式包装它们。

class Class
{
    Class()
    {
        Register([=](int n){ Function(n); });
    }

    void Register(std::function<void(int)> Callback)
    {

    }

    void Function(int Number)
    {

    }
};

但我想直接绑定它们,如下所示。

// ...
Register(&Class::Function);
// ...

我觉得按照C++11标准,这个应该是支持的。但是,在 Visual Studio 11 中,我得到了这些编译器错误。

错误 C2440: 'newline' : 无法从 'int' 转换为 'Class *'

错误 C2647: '.*' : 无法取消引用 'int' 上的 'void (__thiscall Class::* )(int)'

【问题讨论】:

    标签: c++ c++11 member-functions std-function


    【解决方案1】:

    我觉得按照C++11的标准,这个应该是支持的

    不是真的,因为一个非静态成员函数有一个隐式的第一个参数类型(cv-qualified)YourType*,所以在这种情况下它不匹配void(int)。因此需要std::bind:

    Register(std::bind(&Class::Function, PointerToSomeInstanceOfClass, _1));
    

    例如

    Class c;
    using namespace std::placeholders; // for _1, _2 etc.
    c.Register(std::bind(&Class::Function, &c, _1));
    

    编辑您提到这将使用相同的Class 实例调用。在这种情况下,您可以使用简单的非成员函数:

    void foo(int n)
    {
      theClassInstance.Function(n);
    }
    

    然后

    Class c;
    c.Register(foo);
    

    【讨论】:

    • 可以,但是在所有类引用都相同的约束下可以简化语法吗?
    • @danijar 所有类引用都相同是什么意思?您需要将指针传递给Class 实例。你通过哪一个取决于你。
    • 对。这个实例将永远是一样的。现在我想根据这些信息缩短bind(&amp;Class::Function, this, _1)。所以,从内容上讲,bind 已经过时了。有没有什么技术方法可以去掉或者通过后在函数内部进行绑定?
    • @danijar 会是某种全局实例还是单例?如果是这样,那么您还可以在绑定到该实例的位置创建一个全局 std::function。然后,您只需重新使用它。实际上,没有必要保留一个全局的std::function。一个简单的非成员函数就可以解决问题。
    • @Sasha 可能是void foo(int n)。固定。
    【解决方案2】:

    根据 Stephan T. Lavavej -“避免使用 bind(),...,使用 lambdas”。 https://www.youtube.com/watch?v=zt7ThwVfap0&t=32m20s

    在这种情况下:

    Class()
    {
        Register([this](int n){ Function(n); });
    }
    

    【讨论】:

    • 感谢您指出这一点并链接到视频的相关部分!
    【解决方案3】:

    你可以使用std::bind:

    using namespace std::placeholders;  // For _1 in the bind call
    
    // ...
    
    Register(std::bind(&Class::Function, this, _1));
    

    【讨论】:

    • 说,我想将此函数指针设置为函数的默认参数。这可能吗?我不能使用像bind 这样的电话,是吗?我没有在参数列表中找到this 指针。
    • @danijar 这是不可能的,但可以通过使用Register 的重载变体来解决,该变体没有绑定到默认函数的参数。
    • 我的代码中缺少 std::placeholders 而这个答案指出了它!
    【解决方案4】:

    在 C++ 17 中,您可以使用:

    Register([=](auto && ...args){ return Function(args...); });
    

    这很甜蜜,尤其是在参数列表较长的情况下。 当然,成员函数的参数列表必须与std::function 的参数列表兼容。

    【讨论】:

      【解决方案5】:

      std::functionstd::bind 可以对不同的类成员函数一视同仁。

      #include <iostream>
      #include <functional>
      #include <vector>
      using namespace std;
      using namespace std::placeholders;
      
      class Foo
      {
      public:
          void foo(const string &msg)
          {
              cout << msg << '\n';
          }
      };
      
      class Bar
      {
      public:
          void bar(const string &msg, const string &suffix)
          {
              cout << msg << suffix << '\n';
          }
      };
      
      int main(int argc, char **argv)
      {
          Foo foo;
          Bar bar;
      
          vector<function<void (const string &msg)>> collection;
          collection.push_back(bind(&Foo::foo, &foo, _1));
          collection.push_back(bind(&Bar::bar, &bar, _1, "bar"));
      
          for (auto f : collection) {
              f("foo");
          }
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-08-22
        • 1970-01-01
        • 1970-01-01
        • 2023-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多