C++ C+中的函数签名差异+;11

C++ C+中的函数签名差异+;11,c++,lambda,c++11,g++,capture,C++,Lambda,C++11,G++,Capture,考虑C++11的lambdas和以下代码 template <typename M> void call(void (*f)(M), M m) { f(m); } int main() { call<int>([](int n) { }, 42); // OK int r; call<int>([&](int n) { r = n; }, 42); // KO } 模板 无效通知(无效(*f)(M),M) {

考虑C++11的lambdas和以下代码

template <typename M>
void call(void (*f)(M), M m)
{
  f(m);
}

int main()
{
  call<int>([](int n) { }, 42);          // OK

  int r;
  call<int>([&](int n) { r = n; }, 42);  // KO
}
模板
无效通知(无效(*f)(M),M)
{
f(m);
}
int main()
{
调用([](int n){},42);//确定
INTR;
调用([&](int n){r=n;},42);//KO
}
lambda之间是否存在签名差异,使得第二个lambda与
call的参数不兼容

我使用g++4.6.1


附带问题:如果我编写
call([](int n){},42),为什么不能推断参数

只有无CaptureLambda可以隐式转换为函数指针

捕获变量的lambda无法转换为函数指针,因为它具有需要维护的状态(捕获的变量),并且该状态不能由函数指针表示


无法从函数参数推断类型
M
,因为需要进行转换才能将lambda转换为函数指针。该转换禁止模板参数推断。如果要使用实际函数(例如,
void f(int)
)调用函数
call
,则参数推断可以正常工作。

正如James已经回答的,只有无捕获lambda可以转换为函数指针。具有状态创建函子对象的lambda实现了
操作符()
,成员函数指针与自由函数指针不兼容

当编译器处理:
[&](int n){r=n;}
时,它会生成如下内容:

class __annonymous_lambda_type {
   int & r;
public:
   __annonymous_lambda_type( int & r ) : r(r) {}
   void operator()( int n ) const {
      r = n; 
   }
} __lambda_instatiation;
该类需要存储lambda的状态,在本例中是对外部对象的引用,该外部对象将在执行lambda时被修改。不能将
void操作符()(int)
绑定到
void(*)(int)


另一方面,如果lambda是无状态的,它可以作为一个自由函数来实现,比如在
[](int n){std::cout注意,
M
是由第二个参数推导出来的。因此,为了实现这一点,我们可以在第一个参数中创建一个非推导上下文。
void调用(void(*f)(typename identity::type),M)
。现在,C++0x需要这项工作。当前的一些编译器将要求整个参数为非推断上下文(comeau不需要,但GCC和clang afaik需要)。因此,为了提高兼容性,可以说
void call(typename identity::type,M)
。因为它是一个非推断上下文,所以不会被比较,也不会导致推断失败。@Johannes:啊,斯里克。我不知道非推断上下文可以用来积极禁止推断;我认为它只能用于消极禁止推断。太好了!
void __annonymous_lambda_function( int n ) {
   std::cout << "Hi " << n << std::endl;
}