c++ - 绑定(bind)一个本身由 std::bind 创建的函数对象会造成麻烦

标签 c++ c++11

<分区>

bindbind 创建的函数对象作为函数的参数时,我遇到了问题。

我有两个函数 fafbfa 接受一个函数作为参数。我将 fa 和函数(在这种情况下为 fb)绑定(bind)到一个闭包中。我用两种不同的方式来做,如下所示。第一个有效,第二个不编译。

(我知道,我不需要在标记的行上绑定(bind),因为没有参数。当然,这只是展示行为的最小示例,实际上我会将参数绑定(bind)到 fb)

void fa(function<void()> f){
    f();
}

void fb(){

}

void test_which_compiles() {
    auto bb = fb; // *** QUESTIONABLE LINE ***
    auto aa = std::bind(fa, bb);
    aa();
}

void test_which_fails() {
    auto bb = std::bind(fb); // *** QUESTIONABLE LINE ***
    auto aa = std::bind(fa, bb);
    aa(); // COMPILE ERROR HERE
}

调用aa()时出现编译错误。

因此,当我将函数对象绑定(bind)为参数时,编译器似乎不接受它本身是由 bind 创建的。

编译错误是一长串我不认为与该行直接相关的东西。我只给出第一行:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/type_traits:3476:13: error: no matching function for call to '__invoke' __invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...)

编译器是启用了 C++11 的 Apple LLVM 版本 6.1.0 (clang-602.0.53)(基于 LLVM 3.6.0svn)

最佳答案

std::bind返回一些未指定的仿函数,当嵌套在另一个仿函数中时具有神奇的行为 bind表达。您可以通过包装该返回类型来禁用这种神奇的行为,例如。通过声明bb作为:

std::function<void()> bb = std::bind(fb);

如果 bb 真的有参数,这同样有效:

std::function<void()> bb = std::bind(fb, 42);

有关解释,请参阅成员函数运算符() 下的第二个项目符号here :

If std::is_bind_expression<T>::value == true (i.e. another bind subexpression was used as an argument in the initial call to bind), then that bind subexpression is invoked immediately and its result is passed to the invocable object. If the bind subexpression has any placeholder arguments, they are picked from u1, u2, ....

这个例子展示了嵌套的绑定(bind)表达式行为和(我认为)你真正想要的行为。 编辑 - 现在还包括来自评论的 Yakk 的转发包装器:比使用 function 更多的输入或 lambda,但更轻量级。

#include <iostream>
#include <functional>

void f(int n1, int n2, int n3) {
    std::cout << n1 << ' ' << n2 << ' ' << n3 << '\n'; }
void g(int n1, std::function<int()> fun, int n3) {
    std::cout << n1 << ' ' << fun() << ' ' << n3 << '\n'; }
int h(int n) { return n; }

namespace Yakk {
    template <class F> struct f_t {
        F f;
        template <class...Ts>
        std::result_of_t<F const&(Ts...)> operator()(Ts&&...ts) const& {
            return f(std::forward<Ts>(ts)...);
        } /* similar for &, &&, const&& */
    };  

    template <class F> f_t<std::decay_t<F>> f(F&& fin) {
        return {std::forward<F>(fin)};
    }
}

int main() {
    using namespace std::placeholders;
    auto subexpr = std::bind(h, _2);
    auto magic = std::bind(f, _1, subexpr, 42);
    magic(7, 11);

    std::function<int()> nested = std::bind(h, 11);
    auto nomagic = std::bind(g, _1, nested, 42);
    nomagic(7);

    auto yakkmagic = std::bind(g, _1, Yakk::f(std::bind(h, 11)), 42);
    yakkmagic(7);
}

关于c++ - 绑定(bind)一个本身由 std::bind 创建的函数对象会造成麻烦,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32610844/

相关文章:

c++ - VS2013 下的 emplace_back() 问题

c++ - libstdc++ 中允许不兼容的函数类型?

algorithm - 从/向文件读取/写入 std::unordered_map 的更快方法

c++ - 根据 boost::filesystem,为什么这个文件不是常规文件?

c++ - 平台物理弹跳故障 C++

c++ - 是否可以有一个带有参数作为类名 c++ 的构造函数?

c++ - 泛化一个函数

c++ - 错误 : linker command failed with exit code 1 (use -v to see invocation) : on Macbook

C++成员布局

c++ - 对包含整数和字符的字符串数组进行排序