在std::bind表达式中使用Boost适配器



我有以下代码:

#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <functional>
#include <memory>
struct A {
    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
};
struct B {
    B() = default;
    B(const B&) = delete;
    B& operator=(const B&) = delete;
    int foo(const A&, int b)  {
        return -b;
    }
};
int main() {
    A a;
    auto b = std::make_shared<B>();
    std::vector<int> values{1, 2, 3, 2};
    using std::placeholders::_1;
    auto fun = std::bind(&B::foo, b.get(), std::ref(a), _1);
    int min = *boost::min_element(values | boost::adaptors::transformed(fun));
    std::cout << min << std::endl;
}

当我尝试编译它时,clang给出以下错误消息(这里的完整输出):

/usr/local/include/boost/optional/optional.hpp:674:80: error: object of type 'std::_Bind<std::_Mem_fn<int (Base::*)(const A &, int)> (Base *, std::reference_wrapper<A>, std::_Placeholder<1>)>' cannot be assigned because its copy assignment operator is implicitly deleted

虽然bind对象有复制构造函数,但它的复制赋值操作符被删除了。如果我尝试使用lambda而不是bind,我会得到相同的错误。

  1. 这是c++ 11标准、libstdc++实现或Boost适配器实现中的错误吗?

  2. 最好的解决方法是什么?我可以把它包装成一个std::function。看来boost::bind也起作用了。哪个更有效率,或者这真的很重要吗?

问题来了:

  1. 标准没有要求std::bind的返回值是可复制赋值的;只能移动可构造对象(如果所有绑定对象都是可复制构造对象,则只能移动可复制构造对象)。对于lambdas,需要删除其复制赋值操作符

  2. 范围适配器实际上使用transform_iterator,因此函数对象被存储在迭代器中。

  3. 迭代器必须是可复制赋值的,min_element试图这样做,结果你的程序崩溃了。

随着c++ 11中lambdas的激增,我认为这是boost库的问题,它在设计时没有考虑到可复制构造但不可复制赋值的函数对象。

我实际上建议将结果函数对象包装在reference_wrapper:

int min = *boost::min_element(values | boost::adaptors::transformed(std::ref(fun)));

这也节省了每次复制迭代器时复制函子的额外成本。

在您列出的两个选项中,boost::bind应该更有效,因为它不需要进行类型擦除。

相关内容

  • 没有找到相关文章

最新更新