【问题标题】:What is the best type for a callable object in a template method?模板方法中可调用对象的最佳类型是什么?
【发布时间】:2020-03-09 23:17:23
【问题描述】:
每次我写一个接受模板化可调用的签名时,我总是想知道参数的最佳类型是什么。应该是值类型还是 const 引用类型?
例如,
template <class Func>
void execute_func(Func func) {
/* ... */
}
// vs.
template <class Func>
void execute_func(const Func& func) {
/* ... */
}
是否存在可调用大于 64 位(又名指向 func 的指针)的情况?也许std::function 的行为有所不同?
【问题讨论】:
标签:
c++11
templates
lambda
callable
【解决方案1】:
有没有callable大于64bits的情况
根据我在 CAD/CAE 应用程序方面的工作经验,很多。函子可以轻松保存大于 64 位的数据。超过两个ints、不止一个double、不止一个指针,您只需在 Visual Studio 中超过该限制即可。
【解决方案2】:
没有最好的类型。如果你有不可复制的函子怎么办?第一个模板将不起作用,因为它将尝试使用已删除的复制构造函数。您必须移动它,但随后您将失去(可能)该对象的所有权。这完全取决于预期用途。是的,std::function 可以比 size_t 大得多。如果绑定成员函数,它已经是2个字(对象指针和函数指针)。如果你绑定一些参数,它可能会进一步增长。 lambda 也是如此,每个捕获的值都存储在 lambda 中,在这种情况下,它基本上是一个仿函数。如果您的可调用对象具有非 const 运算符,则 const 引用将不起作用。它们都不适合所有用途。有时最好的选择是提供几个不同的版本,这样您就可以处理所有情况,SFINAE 是您的朋友。
【解决方案3】:
一般来说,我不喜欢通过 const 引用传递 callable 对象,因为它不是那么灵活(例如,它不能用于可变 lambda)。我建议按值传递它们。如果您检查 stl 算法实现(例如,std::for_each),所有可调用对象也都按值传递。
这样做,如果需要,用户仍然可以使用std::ref(func) 或std::cref(func) 来避免不必要地复制可调用对象(使用reference_wrapper)。