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

时间:2011-07-27 22:12:57

标签: c++ templates lambda c++11

我的previous question得出结论,使用带有C ++ lambda函数的POSIX makecontext(即函数对象)可能需要令人反感的“双重强制转换”。继续,我现在面临与以下最小代码相关的编译错误:

#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 ......

2 个答案:

答案 0 :(得分:5)

如果使用[=]来诱导lambda,则不会获得函数指针(或可转换为一个的对象)。您将获得一个函数 object 。并且没有任何数量的转换允许您将其传递给makecontext。没有任何实际可行的方式。

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

  

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

这是 only 的地方,规范允许转换为函数指针。因此,如果最新版本的GCC允许转换为[=]的函数指针,则不符合规范。

答案 1 :(得分:3)

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

[=]声明中将[]更改为f,它应该按预期工作。

编辑:这与最新版本的GCC编译(如Kerrek所述)这一事实强烈表明这只是您正在使用的版本中的编译器错误。