【问题标题】:How to indicate the overloaded function of given signature in std::bind?如何在 std::bind 中指示给定签名的重载函数?
【发布时间】:2018-01-10 22:43:55
【问题描述】:

我有 api 函数 f_api(std::function<void(int)> func) 现在我有我的进程类

class Func {
public:
    void operator()(int i) {
        // do some work
    }
    int operator()(int i, int j) {
        // do some other work
    }
};

我想使用Func f f(int i) 传递给 f_api 来完成这项工作;所以我使用 std::bind

Func f;
std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
f_api(func);

但是这里的问题是,我怎样才能指出我想绑定哪个Func::operator()()?我可以通过它的名字给一个成员函数,但是当这个成员函数确实有几个不同的签名重新加载函数时,我该如何处理呢? std::bind 会为我找到最合适的函数吗? C++好复杂.....

最小可验证案例:

#include <iostream>
#include <functional>

using namespace std;

class Func {
public:
    void operator()(int i) {
        // do some work
        cout << "i is: " << i << endl;
    }
    int operator()(int i, int j) {
        // do some other work
    }
};

void f_api(function<void(int)> f) {
    f(3);
}

int main () {
    Func f;
    std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
    f_api(func);
    return 0;
}

编译错误:

a.cpp: In function ‘int main()’:
a.cpp:23:91: error: no matching function for call to ‘bind(<unresolved overloaded function type>, Func*, const std::_Placeholder<1>&)’
     std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
                                                                                           ^
a.cpp:23:91: note: candidates are:
In file included from a.cpp:2:0:
/usr/include/c++/4.8/functional:1655:5: note: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^
/usr/include/c++/4.8/functional:1655:5: note:   template argument deduction/substitution failed:
a.cpp:23:91: note:   couldn't deduce template parameter ‘_Func’
     std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
                                                                                           ^
In file included from a.cpp:2:0:
/usr/include/c++/4.8/functional:1682:5: note: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^
/usr/include/c++/4.8/functional:1682:5: note:   template argument deduction/substitution failed:
a.cpp:23:91: note:   couldn't deduce template parameter ‘_Result’
     std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
                                                                                           ^

在我的情况下,它有点不同,因为我的 class Func 无法分配,因为该类的一个成员字段不可分配,所以在编译期间我会得到一个稍微不同的错误。

【问题讨论】:

  • 尝试过吗?您是否遇到任何错误,或者它是否按预期工作?
  • 我建议你忘记 std::bind 甚至存在。几乎总是 lambda 更容易理解。
  • 是的,我有。当我做f_api(func)。它向我显示了有关函数对象分配不兼容的错误
  • @kay 如果他仅限于 C++11 或 0x,那么在某些情况下他必须优先使用 lambda。加上一些编译器的实现会提示绑定使用。例如。 2012 年之后的任何 Microsoft 编译器。
  • @LiuWeibo - 你也不能轻易地将指针传递给bind 的结果。此外,可以将无捕获 lambda 转换为常规函数指针。 std::bind 的结果不能保证以 IIRC 的这种方式进行转换。

标签: c++ c++11 std stdbind


【解决方案1】:

对于所有的重载,你都可以做到这一点。通过铸造:

using sig1 = void (Func::*)(int);
using sig2 = void (Func::*)(int, int);

std::bind(static_cast<sig1>(&Func::operator()), &f, std::placeholders::_1);

或者,如果您有 lambda,您可能会发现 std::bind 并不是那么有用:

std::function<void(int)> func = [&](int i) { f(i); };

【讨论】:

  • 在这里讨论过stackoverflow.com/questions/17363003/… 问题是大多数流行的编译器没有有效地实现 lambda,并且 C++14 没有得到太多支持。
  • @Swift - 自那篇帖子以来已经有好几年了。编译器支持稳定地变得更好。甚至 MSVC 也有不错的支持(这说明了一些问题)。
  • @StoryTeller 它变得更好,但并不像样。最后一个体面的版本是 2012 年,后来的版本实际上被我工作的关注点禁止使用,尽管每个版本的测试都在不断进行。我们不断地处理这些问题,积累了大约 300 个 MSVC 生成完全错误代码的用例。其中一些你可以在 SO 上找到。最新版本仍然只支持部分 c++11;一时兴起的 c++14 可能会失败,以有限的方式支持 Lamba 代码(可怕的“请简化您的代码”消息)。标准确实存在,但在现实生活中并非所有东西都可以使用。
  • @Swift - 我对使用 MSVC 表示哀悼。除了 Lambda,Microsoft 确实支持 他们 提出的功能足够好。如果你认为我可以在工作中使用所有这些闪亮的玩具,我会让你知道我仍在用 C++03 编程为生。最新和最大的是个人兴趣。
【解决方案2】:

Func 是一个函数对象。与其获取成员函数指针,不如将整个对象交给绑定,并在您使用绑定时让它解析,或者在这种情况下,当您将其添加到 std::function 时。

Func f;
std::function<void(int)> func = std::bind(f, std::placeholders::_1);

甚至更好,只需将 f 分配给 std::function

Func f;
std::function<void(int)> func = f;

【讨论】:

  • 很好地利用了我们面对的显而易见的东西 :) 只有一个需要注意的地方,那就是这会创建 f 的副本。
  • 注意std::function&lt;void(int)&gt; func = f; f 被复制(即使用Func(const Func&amp;))可能很重要。根据您的用例,您可能希望改用 std::function&lt;void(int)&gt; func = std::ref(f);
  • @kay 或 std::move(f)
  • 非常令人印象深刻,谢谢。 std::function func = ref(f);也做好事!
猜你喜欢
  • 2021-04-19
  • 1970-01-01
  • 2012-10-15
  • 1970-01-01
  • 2016-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多