Lambda表达式:N3290草案

4
一个来自n3290 ISO草案的观点: Lambda表达式:5.1.2节,第6段:
         "The closure type for a lambda-expression with no 
      lambda-capture has a public non-virtual non-explicit const
      conversion function to pointer to function having the same
      parameter and return types as the closure type’s function
      call operator. The value returned by this conversion
      function shall be the address of a function that, when
      invoked, has the same effect as invoking the closure
      type’s function call operator."

可以举个例子来解释这个问题吗?

你有没有觉得这个程序的某个部分很难理解?有没有一些术语你不明白?你是否不了解所需的行为是什么? - James McNellis
@ James:typedef int(*pf)(int); int 回调函数(pf func){return func(3);} pf func = [](int k) ->int{ k--; return k;}; - user751747
@ James:上面的例子是否代表了上述语句?我对“与调用闭包类型的函数调用运算符具有相同效果”这一点有些困惑,但我无法通过编程方式证明。 - user751747
简而言之,"非捕获lambda函数*实际上就是普通的自由函数"(只是没有名称)--至少在需要时如此。(例如,您可以将其传递给旧的C sort函数。) - Kerrek SB
2个回答

4

简短回答

这意味着没有捕获任何东西的lambda可以转换为具有相同签名的函数指针:

auto func = [](int x) { return x * 2; };
int (*func_ptr)(int) = func; // legal.

int y = func_ptr(2); // y is 4.

而且截屏是非法的:

int n = 2;
auto func = [=](int x) { return x * n; };
int (*func_ptr)(int) = func; // illegal, func captures n

长篇回答

Lambdas是一种创建函数对象的简写方式:

auto func = [](int x) { return x * 2; };

等同于:

struct func_type
{
    int operator()(int x) const { return x * 2; }
}

func_type func = func_type();

在这种情况下,func_type 是 "闭包类型",operator() 是 "函数调用运算符"。当您获取 lambda 的地址时,就好像声明了 operator() 为静态函数并获取其地址,就像任何其他函数一样:
struct func_type
{
    static int f(int x) { return x * 2; }
}

int (*func_ptr)(int) = &func_type::f;

当你捕获变量时,它们成为func_type的成员。由于operator()依赖这些成员,因此无法将其设置为静态:

struct func_type
{
    int const m_n;

    func_type(int n) : m_n(n) {}
    int operator()(int x) const { return x * m_n; }
}

int n = 2;
auto func = func_type(n);

普通函数没有成员变量的概念,因此如果lambda表达式没有成员变量,那么它们也只能被视为普通函数。


你知道编译器是否应该诊断无捕获吗?例如,如果我写 [=](int x){return x*2;},即使我指定按值捕获,我也没有捕获任何东西。 - Matthieu M.
[=] 仅仅改变了默认的捕获方式 -- 只要你不实际捕获任何东西,你仍然可以转换为函数指针。 - Cory Nelson
@ Cory,这个语句怎么理解:“此转换函数返回的值应为一个函数的地址,当调用该函数时,其效果与调用闭包类型的函数调用运算符相同”,你能解释一下吗? - user751747

2

大致意思是,新的C++0x lambda有一个转换运算符,可以将其转换为一个函数指针(具有相同的签名)。当您调用该函数指针时,就像调用lambda表达式(传递相同的参数)。

...没有lambda-capture的lambda表达式...

“没有lambda-capture”表示您没有从包含作用域中捕获任何变量,因此它是自包含的。

根据这段描述,我认为如果您捕获了变量(例如来自本地作用域),则无法进行转换:

// this is fine...
std::vector<int> some_list;
int total = 0;
std::for_each(some_list.begin(), some_list.end(), [&total](int x) {
  total += x;
});

// so is this...
int total = 0;
auto someLambda = [](int x) { return x * 5; };
int (*pointerToLambda)(int) = someLambda;
someFunction(pointerToLambda);

// this won't work, because of capture...
int total = 0;
auto someLambda = [&total](int x) { total += x; return total; };
int (*pointerToLambda)(int) = someLambda;
someFunction(pointerToLambda);

如果你捕获到任何东西,他们不会保证它,因为他们无法保证。捕获的值存储在对象中,因此它的operator()不能是静态的,因此它不能转换为静态/非成员函数指针。 - Jan Hudec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接