在C++中传递函数
Passing functions in C++
假设我想编写一个调用空函数 100 次的函数。 这些实现中哪一个是最好的,为什么?
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(const F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
还是有更好的实现?
关于 4 的更新
struct S {
S() {}
S(const S&) = delete;
void operator()() const {}
};
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
int main() {
const S s;
call100(s);
}
我会使用第一个(按值传递可调用的)。
如果调用方担心复制可调用对象的成本,则可以使用std::ref(f)
或std::cref(f)
通过reference_wrapper
传递它。
通过这样做,您可以为调用方提供最大的灵活性。
唯一的运行时成本
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; ++i)
f();
}
是如果你以多种方式传递f
,它可以有更多的版本(代码副本)。 使用 MSVC 或带有 ICF 的黄金链接器,这些副本只会花费编译时间,除非它们不同,如果它们不同,您可能希望保留它们。
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; ++i)
f();
}
这个具有价值语义的优点;遵循取值的规则,除非你有充分的理由不这样做是合理的。std::ref
/std::cref
允许您使用持久引用来调用它,对于 prvalues C++17,保证省略将防止虚假副本。
开个玩笑,你可以做:
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 99; ++i)
f();
std::forward<F>(f)();
}
但这依赖于人们operator()
&&
过载,而没有人这样做。
我认为没有明确的答案:
-
第一个复制您传递的所有内容,这些内容可能很昂贵 用于捕获 lambda,但在其他方面提供了最大的灵活性:
优点
- 允许的常量对象
- 允许(复制)可变对象
- 可以省略副本(?
缺点
- 复制您提供的所有内容
- 如果不复制它,则无法使用现有对象(例如可变 lambda)调用它
-
第二个不能用于常量对象。另一方面 它不复制任何内容并允许可变对象:
优点
- 允许的可变对象
- 不复制任何内容
缺点
- 不允许常量对象
-
第三个不能用于可变的 lambda,所以有点 修改第二个。
优点
- 允许的常量对象
- 不复制任何内容
缺点
- 不能使用可变对象调用
-
第四个不能用 const 对象调用,除非你复制 他们变得非常尴尬 与 lambdas.您也不能使用 它与预先存在的可变 lambda 对象不复制它或 从它移动(在此过程中丢失它)是类似的 限制为 1。
优点
- 如果需要副本,则通过强制(要求)移动语义来明确避免复制
- 允许可变对象。
- 允许的 const 对象(可变 lambda 除外)
缺点
- 不允许没有副本的常量可变 lambda
- 您不能使用现有对象(例如可变 lambda)调用它
你有它。这里没有灵丹妙药,每个版本都有不同的优缺点。我倾向于第一个是默认值,但对于某些类型的捕获 lambda 或更大的可调用对象,这可能会成为一个问题。并且您不能使用可变对象调用 1) 并获得预期的结果。如其他答案所述,其中一些可以通过std::ref
和其他操作实际T
类型的方法来克服。根据我的经验,这些往往是非常讨厌的错误的来源,尽管当T
与人们期望实现的不同时,即副本的可变性等。
- 通过键入的引用问题传递函数
- 通过两个嵌套函数传递C++函数的名称
- 如何从模板类传递函数
- 从私有函数传递函数作为参数
- 如何通过模板传递函数?
- 传递函数指针时未解析的外部符号
- 传递函数指针代替插槽函数
- 如何在 arduino 中传递函数参数
- "double(*)(string, double, double)"尝试传递函数C++时"double"转换错误
- 按引用传递函数参数
- 如何在类(C )中作为参数传递函数
- 在检查传递函数标识符时是否获得模板参数时遇到问题
- 在类之间传递函数指针
- 在C++中传递函数
- 为什么这是一个按指针传递函数
- 当指针具有可选参数时,如何传递函数指针
- C++模板在传递函数签名时未进行编译
- 是否可以通过引用传递函数对象
- C++传递函数作为具有多态类型的参数
- 通过引用或值传递函数