如果 lambda 没有指定的类型,std::function 如何接受 lambda?



有人能解释lambda函数在std::function中是如何表示的吗?编译器是否进行了隐式转换,std::函数是否用作容器?

我最近问了一个稍微不同的问题,这个问题被标记为这个问题的重复。答案是lambda函数的类型未定义且未指定。我发现一些代码似乎为lambda函数提供了一个容器,如下所示。我还引用了Stroustrup的一句话,这似乎与lambda函数没有定义类型的说法相矛盾,但它是一个函数闭包类型。这只会使事情更加混乱。

更新:关于函数实现的部分答案<>就在这里。

感谢您的指导。

#include <iostream>
#include <vector>
#include <functional>
using namespace std;
static vector<function<void(int)>> cbl;
static vector<function<int(int)>> cblr;
class GT {
public:
int operator()(int x) {return x;}
};
void f()
{
auto op = [](int x) {cout << x << endl;}; 
cbl.push_back(op);
for (auto& p : cbl)
p(1);
auto op2 = [](int x) {return x;};
cblr.push_back(op2);
cblr.push_back(GT());
for (auto& p : cblr)
cout << p(99) << endl;
}
int main(int argc, char *argv[])
{
f();
return 0;
}

编译和结果:

g++ -pedantic -Wall test130.cc && ./a.out
1
99
99

Stroustrup在C++第4版第297页中谈到了这一点:

为了允许lambda表达式的优化版本未定义lambda表达式。然而,它被定义为§11.4.1中所示样式的函数对象的类型。这类型,称为闭包类型,对于lambda是唯一的,因此没有两个Lambda有相同的类型。有两个Lambda有相同的类型模板实例化机制可能已经融合。A.lambda是具有构造函数和常量成员的本地类类型函数运算符()()。

类型就在那里。只是你事先不知道它是什么。Lambdas有类型——只是标准没有说明那种类型是什么;它只提供type必须履行的合同。这取决于编译器实现者来决定该类型到底是什么。他们不必告诉你。知道是没有用的。

因此,您可以像处理任何"通用"类型的存储一样处理它。即:提供适当对齐的存储,然后使用放置new复制构造或移动构造该存储中的对象。这些都不是std::function特有的。如果你的工作是编写一个可以存储任意类型的类,你就会这么做。这也是std::function必须做的。

std::function的实现者通常采用小对象优化。这个班在教室里留了一些没用的房间。如果要存储的对象是空房间适合的对齐方式,并且它将适合未使用的房间,则存储将来自std::function对象本身。否则,它将不得不为其动态分配内存。这意味着,例如,捕获内部向量类型(AVX、Neon等)(如果可能的话)通常会使lambda不适合std::function中的小对象优化存储。

我没有声称捕获内在向量类型是否是允许的、富有成效的、合理的,甚至是可能的。这有时是一个充满角落案例和微妙平台漏洞的雷区。我不建议任何人在没有充分了解发生了什么,以及在需要时审计组装结果的能力的情况下去做这件事(这意味着:在压力下,通常是在演示日凌晨4点,西装很快就要醒了——他们已经很恼火了,因为他们不得不在一天中这么早就中断高尔夫比赛,只是为了看着演讲者流汗)

"没有类型"one_answers"类型未指定"之间有区别。未指定意味着它存在,但不知道它是什么。也就是说,它没有可以键入的类型名称,但它有类型。

示例中的op是一个具有类型的变量。你不知道什么有效的字母组合可以识别该类型的名称(事实上,没有有效的字母结合可以识别该类的名称)。但是类型可以通过decltype(op)来计算。

lambda有一个类型。您可以编写一个接受lambda并调用它的函数模板:

template<typename T>
class F{
T t;
public:
F(const T &lambda):t(lambda){}
void call() {t();}
};

这是std::function的一个非常基本的方法

"编译器和std::函数用作容器是否进行了隐式转换?">否,不需要转换它们。

你一直在反复声称lambdas"没有类型",但这不是"未指定"的意思,也不是任何人在最后三个问题上说的意思。

Lambdas有一个类型,你只是不知道类型的名称

该标准没有指定任何lambda类型的名称。如果这样的类型甚至有一个名称,编译器的内部工作就会知道,typeid().name()可能会显示它,错误消息通常会显示它

但你不知道,也不可能提前知道任何给定lambda的类型的名称。这是故意的。因此,您不能在源代码中写出该类型。这很好;你为什么要这样做?

Templates和auto不需要名称,因为模板就是这样工作的。std::function的内部工作不需要知道任何lambda类型的名称;他们只需要知道表达式CCD_ 13是否有效。

最新更新