模板方法中可调用对象的最佳类型是什么?

What is the best type for a callable object in a template method?

每次我写一个接受模板化调用的签名时,我总是想知道参数的最佳类型是什么。应该是值类型还是const引用类型?

例如,

template <class Func>
void execute_func(Func func) {
    /* ... */
}

// vs.

template <class Func>
void execute_func(const Func& func) {
    /* ... */
}

是否存在可调用对象大于 64 位(又名指向 func 的指针)的情况?也许 std::function 表现不同?

Is there any situation where the callable is greater than 64bits

根据我在 CAD/CAE 应用程序中的工作经验,很多。 Functor 可以很容易地保存大于 64 位的数据。超过两个 int,超过一个 double,超过一个指针,就可以超过 Visual Studio.

中的限制

没有最好的类型。如果你有不可复制的函子怎么办?第一个模板将不起作用,因为它将尝试使用已删除的复制构造函数。您必须移动它,但随后您将失去(可能)该对象的所有权。这完全取决于预期用途。是的,std::function 可以比 size_t 大得多。如果你绑定成员函数,它已经是2个字(对象指针和函数指针)。如果你绑定一些参数,它可能会进一步增长。 lambda 也是如此,每个捕获的值都存储在 lambda 中,在这种情况下它基本上是一个仿函数。如果您的可调用对象具有非 const 运算符,则 Const 引用将不起作用。它们都不是适合所有用途的。有时最好的选择是提供几个不同的版本,这样您就可以处理所有情况,SFINAE 是您的朋友。

一般来说,我不喜欢通过 const 引用传递 callable 对象,因为它不够灵活(例如,它不能用于可变的 lambda)。我建议按价值传递它们。如果您检查 stl 算法实现(例如 std::for_each),所有可调用对象也都是按值传递的。

这样做,如果需要,用户仍然可以使用 std::ref(func)std::cref(func) 来避免不必要的可调用对象复制(使用 reference_wrapper)。