我正在尝试弄清楚如何将
std
函数作为参数传递。这是一个简短的例子:
#include <cmath>
#include <functional>
#include <iostream>
void bar(const double v, std::function<int(int)> foo) {
std::cout << foo(v) << std::endl;
}
int main() {
bar(-23., std::abs);
}
此代码无法编译并显示消息没有匹配函数来调用
bar
,但如果删除std
前缀,一切正常。怎么回事?
std::abs
不是一个功能。它有许多功能,它是一个重载集(参见此处https://en.cppreference.com/w/cpp/numeric/math/abs)。因此,您不能这样获取它的地址。这就是你不能像这样将它传递给其他函数的原因。即使只有一个重载,标准库中的大多数函数也无法获取其地址。只有少数例外。
接下来,当您需要将可调用对象传递给函数时,
std::function
不是要始终使用的 goto 类型。 std::function
适用于需要类型擦除的可调用对象。当你不明白它的意思时没关系,你可以暂时忘记std::function
。当你真正需要它的时候,你就会知道它有什么用。
你可以使用lambda表达式:
template <typename F>
void bar(const double v, F&& foo) {
std::cout << foo(v) << std::endl;
}
int main() {
bar(-23.,[](double a){ return std::abs(a);});
}
请注意,
[](auto a) { return std::abs(a); }
也可以。它会产生一个带有模板化 operator()
的类,该类在调用时被实例化。但是,您不能对函数模板执行相同的操作。
如果想避开模板,可以使用函数指针:
using func_t = double(*)(double);
void bar(const double v, func_t foo) {
std::cout << foo(v) << std::endl;
}
如果去掉
std
前缀,那么只有一个重载继承自C:https://en.cppreference.com/w/c/numeric/math/abs。其他的是C++添加的。请注意,当与using namespace std;
.结合使用时,这可能会产生特别糟糕的后果