std::function
,但我不知道以下语法的含义。std::function<void()> f_name = []() { FNAME(); };
使用
std::function
的目标是什么?是为了创建一个指向函数的指针吗?std::function
,但我不知道以下语法的含义。std::function<void()> f_name = []() { FNAME(); };
std::function
的目标是什么?是为了创建一个指向函数的指针吗?std::function
是一种类型擦除对象。这意味着它擦除了某些操作发生的细节,并为它们提供了统一的运行时接口。对于std::function
来说,主要的操作是复制/移动、销毁和使用operator()
进行'调用',也就是'函数式调用运算符'。
用更简单的英语来说,这意味着std::function
可以包含几乎任何像函数指针一样调用的对象。
它支持的签名放在尖括号内:std::function<void()>
不带参数并且不返回任何值。std::function< double( int, int ) >
带有两个int
参数并返回double
。一般来说,std::function
支持存储任何类似函数的对象,其参数可以从其参数列表进行转换,返回值可以转换为其返回值。
重要的是要知道std::function
和lambda表达式是不同的,尽管它们是兼容的。
()
调用的对象。这样的对象可以进行类型擦除并存储在std::function
中,但会带来一些运行时开销。[](){ code }
是一个非常简单的lambda表达式。它对应于以下内容:struct some_anonymous_type {
some_anonymous_type() {}
void operator()const{
code
}
};
[ capture_list ]( argument_list )
-> return_type optional_mutable
{
code
}
[ capture_list ]
< template_params > requires_clauses
attributes ( argument_list )
-> return_type
{
body
}
operator()
的参数,而return type对应于返回类型。当使用capture_list创建实例时,lambda实例的构造函数也会被神奇地调用。[ capture_list ]( argument_list ) -> return_type { code }
struct some_anonymous_type {
// capture_list turned into member variables
some_anonymous_type( /* capture_list turned into arguments */ ):
/* member variables initialized */
{}
return_type operator()( argument_list ) const {
code
}
};
[]<typename T>( std::vector<T> const& v ) { return v.size(); }
并且属性c++20和要求子句c++23也可以与lambda一起使用。
[]
之后的模板参数适用于operator()
而不是整个lambda。即:
template<class T>
auto foo = [](T t) { return t+1; };
模板
变量,而auto foo = []<class T>(T t) { return t+1; };
template
operator()
的变量。
让我们分开看这行代码:
std::function
这是一个声明,用于声明一个不带参数且不返回值的函数。如果该函数返回一个 int
类型的值,代码应该如下所示:
std::function<int()>
同样地,如果它还需要一个整型参数:std::function<int(int)>
我猜你最大的困惑在于接下来的部分。
[]() { FNAME(); };
[]
部分被称为 捕获子句。在这里,您可以放置对于 lambda 声明局部的变量,并且您希望这些变量在 lambda 函数内部可用。如果这是在类定义内部,并且您想让该类对 lambda 可用,您可能会这样做:
[this]() { FNAME(); };
下一个部分是传递给Lambda表达式的参数,与普通函数完全相同。正如之前提到的,std::function<void()>
是指向不带参数的方法的签名,因此此处也为空。
剩下的部分是Lambda表达式本身的主体,就像它是一个普通函数一样,我们可以看到它只调用了函数FNAME
。
另一个例子
假设你有以下签名,用于对两个数字求和。
std::function<int(int, int)> sumFunc;
我们现在可以这样声明一个 lambda:sumFunc = [](int a, int b) { return a + b; };
不确定您是否使用MSVC,但无论如何这里都有一个关于lambda表达式语法的链接:
[](int a, int b) { return a + b; };
是一个 lambda 函数,它接受两个 int
类型的参数,并返回它们的和。[int a, int b]() { return a + b; };
也是一个 lambda 函数,但它没有参数列表。它通过捕获 [int a, int b]
引入了两个局部变量 a
和 b
,并返回它们的和。因此,两个 lambda 函数都执行相同的操作,但方式略有不同:第一个 lambda 函数接受参数,而第二个 lambda 函数通过捕获引入变量。 - user2982229a
和 b
,另一个则以 a
和 b
作为参数进行调用。 - Yakk - Adam Nevraumontstd::function
只有一个模板参数,因此它没有逗号。一个模板参数必须是一个函数类型。在C++中,ReturnType(Arg1, Arg2)
的语法就是你如何写一个函数类型。 - MSalterstemplate< class R, class... Args >
,它需要(1 + n)个参数,第一个是返回类型,然后是n个参数。我原以为我们应该像这样实例化它 - std::function<int, int, int>
(需要2个int并返回一个int)。但我不知道您也可以像这样实例化它 - std::function<int(int, int)>
。CppReference中也提到了同样的内容 - class function<R(Args...)>;
- NightFuryLxD带捕获的Lambda表达式(有状态的Lambda)由于具有唯一的类型,即使它们看起来完全相同,也不能互相赋值。
为了能够存储和传递带捕获的Lambda表达式,我们可以使用“std::function”来保存由Lambda表达式构造的函数对象。
基本上,“std::function”是为了能够将具有不同内容结构的Lambda函数分配给一个Lambda函数对象。
示例:
auto func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //ATTENTION(ERROR!): assigning a new structure to the same object
cout << "x:" << x << ",a:" << a << endl;
};
func(2);
因此,上述用法是不正确的。 但是如果我们使用“std :: function”定义函数对象:
auto func = std::function<void(int)>{};
func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //CORRECT. because of std::function
//...
};
int y = 11;
func = [x,y](int a){ //CORRECT
//...
};
std::function
,而是关于lambda表达式。 - chris