C++ 函数对象的正确参数类型是什么?

C++ 函数对象的正确参数类型是什么?,c++,function-object,C++,Function Object,我有一个接收函数对象的模板函数。有时函数对象是无状态结构,但有时它们是大型有状态对象。函数对象的状态在此函数中未更改,仅检查。我也非常热衷于编写编译器可以尽可能优化的代码。选择参数类型时应该考虑什么? 该功能属于以下类型: template<typename funcT> auto make_particle(funcT fun) { Particle<typename funcT::result_type> particle; particle = fun(

我有一个接收函数对象的模板函数。有时函数对象是无状态结构,但有时它们是大型有状态对象。函数对象的状态在此函数中未更改,仅检查。我也非常热衷于编写编译器可以尽可能优化的代码。选择参数类型时应该考虑什么?

该功能属于以下类型:

template<typename funcT>
auto make_particle(funcT fun) {
   Particle<typename funcT::result_type> particle;
   particle = fun();
   return particle;
}
模板
自动生成粒子(功能有趣){
颗粒;
粒子=乐趣();
返回粒子;
}

参数类型可能应该是
funcT const&fun
,这样就不会复制大型对象,但是为什么大多数人使用按值调用函数对象呢?我是否通过使用常量引用丢失了某些内容?还是应该使用左值引用?请注意,c++1y是可以的,上面的代码示例只是一个示例。

有几个用例,它们都应该可用:

  • 函子没有状态,作为临时提供:
    make\u particle(MyFun())

  • 函子有一个需要稍后恢复的状态:
    yourf;使_粒子(f)

不能用一个引用类型参数同时解决这两种情况:第一种情况需要常量左值引用或右值引用,这将禁止第二次使用,第二种情况需要左值引用,这将禁止第一次使用

在这种情况下,一个常见的习惯用法是按值接受函子,并在末尾返回它:

template <typename Iter, typename F>
F map(Iter first, Iter last, F f)
{
    // ... f(*first) ...
    return f;
}
模板
F图(Iter优先,Iter最后,F)
{
//…f(*第一)。。。
返回f;
}
这可能不完全适用于你的情况,但这是一个想法。例如,您可以返回一个
std::pair
。在任何情况下,您都需要函子类型是可复制的,但这是一个合理的要求

@Xeo指出的另一种方法(仅适用于函数模板)是通过通用引用获取函子参数,这在两种情况下都有效:

template <typename Iter, typename F>
void map(Iter first, Iter last, F && f)
{
    // ... use f(*first) ...
}
模板
无效图(Iter优先,Iter最后,F&F)
{
//…使用f(*首先)。。。
}
请注意,在这种情况下,我们不使用
std::forward
,因为我们使用
f
作为真正的引用,而不仅仅是将其传递到其他地方。特别是,如果我们仍计划使用它,则不允许我们从
f
移动

参数类型可能应该是funcT const&fun,以便 大型对象不会被复制

这不是标准库中的算法所持的观点。在这里,可调用对象是按值获取的。由可调用对象的作者来确保它的复制成本合理。例如,如果它需要访问大型对象,那么您可以让函子的用户提供对某个对象的引用,并将其存储在函子中——复制引用是便宜的


现在,您可能希望做一些与标准库不同的事情,因为您希望粒子生成函数非常难以复制或移动。不过C++程序员熟悉复制的函子,所以如果你做标准库的操作,那么你通常不会让他们的生活比以前更糟。复制函子不是问题,除非您将其设置为:-)

您可以使用单个引用参数-t&&,也称为通用引用来轻松解决这两种情况。@Xeo:最初我想提供一个函数,而不是模板,所以我在寻找单个解决方案。当然,你是对的,因为我们已经有了模板,我们也可以使用它们。