0

我有以下代码:

#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

似乎虽然绑定对象有一个复制构造函数,但它的复制赋值运算符被删除了。如果我尝试使用 lambda 而不是bind.

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

  2. 最好的解决方法是什么?我可以把它包装成一个std::function. 似乎boost::bind也有效。哪个更有效,还是真的很重要?

4

1 回答 1

4

这是问题所在:

  1. 该标准不要求std::bind' 的返回值是可复制分配的;仅可移动构造(如果所有绑定对象也是可复制构造的,则可复制构造)。对于 lambda,它们的复制赋值运算符需要被删除。

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

  3. 迭代器必须是可复制分配的,min_element尝试这样做,你的程序就会崩溃。

随着 C++11 中 lambdas 的激增,我认为这是 boost 库的一个问题,它在设计时并未考虑到可复制构造但不可复制可分配的函数对象。

我实际上建议将生成的函数对象包装在 a 中reference_wrapper

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

这也节省了复制迭代器时额外复制仿函数的成本。

In the two options you listed, boost::bind should be more efficient because it doesn't have to do type erasure.

于 2015-05-27T22:40:59.133 回答