我有以下代码:
#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会给出以下错误消息(完整输出here):
/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
,我会得到同样的错误。
这是C ++ 11标准,libstdc ++实现还是Boost适配器实现中的错误?
最佳解决方法是什么?我可以将它包装成std::function
。 boost::bind
似乎也有效。哪个更有效率,还是真的重要?
答案 0 :(得分:3)
问题在于:
该标准不要求std::bind
的返回值可复制分配;只能移动可构造(如果所有绑定对象也是可复制的,则可复制构造)。对于lambdas,需要删除它们的复制赋值运算符。
范围适配器实际使用transform_iterator
,因此函数对象存储在迭代器中。
迭代器必须是可复制的,min_element
尝试这样做,并且程序会爆炸。
随着C ++ 11中lambdas的激增,我认为这是一个升级库的问题,它没有考虑到copy-constructible-but-copy-assignable函数对象。
我实际上建议将结果函数对象包装在reference_wrapper
:
int min = *boost::min_element(values | boost::adaptors::transformed(std::ref(fun)));
每当复制迭代器时,这也节省了制作仿函数额外副本的成本。
在您列出的两个选项中,boost::bind
应该更有效率,因为它不需要进行类型擦除。