Lambda返回lambda错误地推断返回类型?

时间:2013-05-24 00:25:03

标签: c++ visual-studio-2012 compiler-construction c++11 lambda

这个问题是我最近一个问题的延续:
What is this compiler error when using a lambda as a template parameter?

十一月2014年11月11日:微软已经回复说,这个bug的修复程序应该出现在Visual C ++的下一个主要版本中。


此代码无法使用VS2012(Update 2)进行编译:

int main(int argc, char* argv[])
{
    auto f = []()
    {
        int n = 0;
        auto r = [=]{ return n; };
        return r;
    };
    return 0;
}

这是我得到的编译器错误:

1>  main.cpp
1>C:\test\main.cpp(7): error C2440: 'return' : cannot convert from 'main::<lambda_c5d1d707b91a1ddedc06eb080503550c>::()::<lambda_ac357c309731f4971c3269160ed9c24b>' to 'int (__cdecl *)(void)'
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

  • 根据C ++ 11规范,代码是否有问题?
  • 根据VS2012定义的部分C ++ 11支持,代码是否有问题?
  • 或者这是VS2012 C ++编译器错误吗?

  • 有人能指出我在C ++ 11规范中讨论lambdas必须如何隐式转换为函数指针的地方吗?
    • 我记得这只适用于无状态 lambdas - 那些带有空捕获子句的内容 - 内部lambda r 不是
    • 那么为什么看起来lambda f的推断返回类型是一个函数指针,即int (__cdecl *)(void)

1 个答案:

答案 0 :(得分:2)

尽管GCC 4.7.2编译了这段代码,但它形成了错误。初始化f的lambda表达式太复杂,无法推断返回类型。确实,5.1.2 / 4说

  
    

如果lambda表达式不包含trailing-return-type,那就好像trailing-return-type表示以下类型:

         

- 如果复合语句的格式为

   { attribute-specifier-seq[opt] return expression ; }
         

lvalue-to-rvalue转换(4.1),数组到指针转换(4.2)和函数到指针转换(4.3)之后返回表达式的类型;

         

- 否则,无效。

  

因此,在此示例中,返回类型为void,但lambda返回其他内容。代码不应该编译。

我同意Visual Studio提供的消息具有误导性。

更新:关于这个问题

  
    

所以说&#34;在C ++ 11中,你不能定义一个返回有状态lambda的lambda&#34 ;?

  

没有。根据下面的C ++ 11引用,lambda返回的类型是void,除非lambda的主体只包含一行return expression;。因此,如果您设法在返回表达式中创建有状态lambda,那么这很好。例如,下面的代码在GCC 4.7.2,Clang 3.2和Intel编译器13.1.0中编译:(由于上述错误,它在VS2012中无法编译。)

#include <iostream>

int main() {
  int n = 5;
  auto f = [=] {
      return [=]{ return n; }; // creates a stateful lambda and returns it in a single line
  };
  std::cout << f()() << std::endl;
  return 0;
}