5

这个问题是我最近的一个问题的延续:
当使用 lambda 作为模板参数时,这个编译器错误是什么?

2014 年 11 月 11 日:微软回应称,这个错误的修复应该出现在 Visual C++ 的下一个主要版本中。


此代码无法使用 VS2012(更新 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 规范中讨论 lambda 必须如何隐式转换为函数指针的地方吗?
    • 我记得这仅适用于状态lambda - 那些带有空捕获子句的 - 内部 lambdar不是
    • 那么为什么推断的 lambda 的返回类型似乎f是一个函数指针,即int (__cdecl *)(void)
4

1 回答 1

2

尽管 GCC 4.7.2 编译了这段代码,但它的格式不正确。初始化的 lambda 表达式f对于推导返回类型来说太复杂了。确实,5.1.2/4 说

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

— 如果复合语句的形式为

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

左值到右值转换(4.1)、数组到指针转换(4.2)和函数到指针转换(4.3)后返回表达式的类型;

——否则,无效。

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

我同意 Visual Studio 给出的信息具有误导性。

更新:关于这个问题

那么说“在 C++11 中,您不能定义返回有状态 lambda 的 lambda”是否正确?

不。根据下面的 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;
}
于 2013-05-24T15:37:27.483 回答