模板函数在与本地lambda一起使用时会导致编译器错误

Template function causes a compiler error when used with local lambda

本文关键字:错误 编译器 一起 函数 lambda      更新时间:2023-10-16

我之前的问题得出的结论是,使用POSIX makecontext与c++ lambda函数(即函数对象)可能需要一个令人讨厌的"双强制转换"。继续,我现在面临一个与以下最小代码相关的编译错误:

#include <iostream>
#include <ucontext.h>
using namespace std;
template <typename T> void foo()   {
  ucontext_t c;
  auto f = [=](int i){ cout << i << endl; };
  makecontext(&c, (void (*) (void)) (void (*)(int)) f, 1, 12345);
}
int main(int argc, char *argv[]) {
  foo<int>();
  return 0;
}

错误是:

error: invalid cast from type ‘foo() [with T = int]::<lambda(int)>’ to type ‘void (*)(int)’

然而,如果我从foo函数中删除未使用的(在本例中)模板参数,那么它将成为void foo();,并将调用更改为foo(),错误就会消失。有人能告诉我为什么吗?我使用的是g++ 4.6.

编辑:

从下面的注释来看,上面代码中的[=]似乎导致lambda成为"捕获"lambda,而不管它实际上没有捕获任何东西。[=]在我的代码中不是必需的,唉,在GCC 4.6中替换为[]并不能消除错误。我正在安装GCC 4.6.1…

如果使用[=]来诱导lambda,则不会得到函数指针(或可转换为函数指针的对象)。您将得到一个函数对象。再多的强制类型转换也不能让你把它传递给makecontext。这根本行不通。

根据N3291, c++ 0x最新的工作草案:

没有lambda捕获的lambda表达式的闭包类型具有一个公共非虚非显式const转换函数,该转换函数指向与闭包类型的函数调用操作符具有相同形参和返回类型的函数。该转换函数返回的值应为另一个函数的地址,该函数在调用时与调用闭包类型的函数调用操作符具有相同的效果。

这是规范允许转换为函数指针的惟一位置。因此,如果最近版本的GCC允许将[=]转换为函数指针,那是不符合规范的。

只有不可捕获的lambda才可以转换为函数指针;虽然f在技术上不捕获任何东西,但它确实有一个按值捕获的默认捕获模式(没有明显的原因)。

f的声明中将[=]更改为[],它应该可以正常工作。

EDIT:事实上,这与最新版本的GCC(正如Kerrek所指出的)一起编译,这强烈表明这仅仅是您正在使用的版本中的编译器错误。