我有一个接收函数对象的模板化函数。有时函数对象是无状态结构,但有时它们是大型有状态对象。函数对象的状态在此函数中未更改,仅进行了检查。我也非常热衷于编写编译器可以尽可能优化的代码。选择参数类型时我应该考虑什么?
该功能属于这种类型:
template<typename funcT>
auto make_particle(funcT fun) {
Particle<typename funcT::result_type> particle;
particle = fun();
return particle;
}
参数类型应该是funcT const & fun
,以便不复制大对象,但为什么大多数人都使用按值调用的函数对象?我是否通过使用const引用来松散?或者我应该使用左值参考?请注意,c ++ 1y没问题,上面的代码示例只是一个例子。
答案 0 :(得分:8)
有几个用例,应该都可用:
仿函数没有状态,是临时提供的:make_particle(MyFun())
仿函数的状态需要稍后恢复:YourFun f; make_particle(f);
你不能用一个引用类型参数来解决这两种情况:第一种情况需要一个const左值引用或一个rvalue引用,它禁止第二次使用,第二种情况需要一个左值引用,它禁止第一次使用。 / p>
在这种情况下常见的习语是按值接受仿函数,最后返回:
template <typename Iter, typename F>
F map(Iter first, Iter last, F f)
{
// ... f(*first) ...
return f;
}
但这可能并不完全适用于您的情况,但这是一个想法。例如,您可以返回std::pair<ParticleType, F>
。在任何情况下,你都要求你的仿函数类型是可复制的,但这是一个合理的要求。
@Xeo有用地指出并且仅用于函数模板的替代方法是通过通用引用来获取functor参数,这将适用于两种情况:
template <typename Iter, typename F>
void map(Iter first, Iter last, F && f)
{
// ... use f(*first) ...
}
请注意,在这种情况下,我们不使用std::forward
,因为我们使用f
作为真正的参考,而不仅仅是将其传递到其他地方。特别是,如果我们仍然打算使用它,我们不允许从f
移动。
答案 1 :(得分:5)
参数类型应该是funcT const&amp;好玩的 不复制大对象,
这不是标准库中算法的视图。在那里,可调用对象按值获取。由可调用对象的作者来确保复制合理便宜。例如,如果它需要访问大的东西,那么你可以让仿函数的用户提供对一个的引用并将其存储在仿函数中 - 复制引用很便宜。
现在,您可能希望以不同于标准库的方式执行操作,因为您希望粒子制作功能异常难以复制或移动。但是C ++程序员熟悉复制的仿函数,所以如果你做了标准库所做的事情,那么通常你不会让他们的生活比现在更糟。复制仿函数不是问题,除非你把它变成一个: - )