Lambda的显式返回类型


91

当我尝试编译此代码(VS2010)时,出现以下错误: error C3499: a lambda that has been specified to have a void return type cannot return a value

void DataFile::removeComments()
{
  string::const_iterator start, end;
  boost::regex expression("^\\s?#");
  boost::match_results<std::string::const_iterator> what;
  boost::match_flag_type flags = boost::match_default;
  // Look for lines that either start with a hash (#)
  // or have nothing but white-space preceeding the hash symbol
  remove_if(rawLines.begin(), rawLines.end(), [&expression, &start, &end, &what, &flags](const string& line)
  {
    start = line.begin();
    end = line.end();
    bool temp = boost::regex_search(start, end, what, expression, flags);
    return temp;
  });
}

我如何指定lambda具有“ void”返回类型。此外,如何指定lambda具有“ bool”返回类型?

更新

以下编译。有人可以告诉我为什么编译而另一个不编译吗?

void DataFile::removeComments()
{
  boost::regex expression("^(\\s+)?#");
  boost::match_results<std::string::const_iterator> what;
  boost::match_flag_type flags = boost::match_default;
  // Look for lines that either start with a hash (#)
  // or have nothing but white-space preceeding the hash symbol
  rawLines.erase(remove_if(rawLines.begin(), rawLines.end(), [&expression, &what, &flags](const string& line)
  { return boost::regex_search(line.begin(), line.end(), what, expression, flags); }));
}

6
您可以使用->,例如[&](double d) -> double { //...
Flexo

2
我建议您仅隐式捕获所需的变量(仅[&]...),因为当前所拥有的是不必要的冗长。
Xeo 2012年

2
[&expression, &start, &end, &what, &flags]...(您的)vs [&]...(我的)。现在告诉我谁更冗长。;)[&]告诉lambda通过引用捕获您在lambda主体中使用的所有内容。这称为“捕获默认值”。另一个是[=]并且将通过副本捕获。
Xeo 2012年

1
@ Xeo,Effective Modern C ++,第31项,建议显式捕获,以避免悬挂引用。我曾几次被自己咬伤,作为对懒惰的惩罚...呃,简洁。:-)
Emile Cormier

2
顺便说一下,减少了对C ++ 14中推导的返回类型lambda的约束。可以为主体中具有多个语句的lambda推导返回类型,并且只要每个return语句的表达式具有相同的类型,您现在就可以拥有具有多个return语句的推导返回类型。
安东尼·霍尔

Answers:


188

您可以-> Type在参数列表之后使用来显式指定lambda的返回类型:

[]() -> Type { }

但是,如果一个lambda有一个语句,而该语句是一个return语句(并且它返回一个表达式),则编译器可以从该一个返回表达式的类型中推断出返回类型。您的lambda中有多个语句,因此不会推断出类型。


4
编译器可以做到这一点,但是标准禁止它这样做。
Johannes Schaub-litb 2012年

9
-1:这不是编译器错误。该标准对此非常明确:第5.1.2节第4段列出了扣除的方式以及在何种条件下进行扣除。
Nicol Bolas 2012年

2
虽然根据最新草案是不允许的,但我发现最终的规范中实际上允许使用该补丁的注释gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html。有人有最终规格要验证吗?
Eelke

2
我已经广泛使用了lambda表达式,但没有一次明确声明返回类型。即使lambda表达式中有多个return语句,也可以完美地推论return类型(至少在VS2012和VS2013下)。当然,各种return语句需要在同一lambda表达式内匹配。例如,“ auto f = [](int i){if(i> 5)返回true;返回false;};”这样的语句 编译没有问题,如果您调用“ auto b = f(10);”,b将为bool类型,当然是真实的;
精灵

1
return nullptr;可以在类型推导中使用扳手,即使它是有效的,因为无论返回哪种指针类型,它都有效。
Grault 2015年

16

可以推导一个lambda的返回类型(在C ++ 11中),但是只有当只有一条语句,并且该语句是一个return返回表达式的语句(例如,初始化器列表不是表达式)时,才能推论得出。如果您有一个多语句lambda,则假定返回类型为void。

因此,您应该这样做:

  remove_if(rawLines.begin(), rawLines.end(), [&expression, &start, &end, &what, &flags](const string& line) -> bool
  {
    start = line.begin();
    end = line.end();
    bool temp = boost::regex_search(start, end, what, expression, flags);
    return temp;
  })

但是,实际上,您的第二个表达式更具可读性。


很好的例子;nitpick:最后是否缺少函数调用);
kevinarpe

6

您仍然可以返回多个语句:

[]() -> your_type {return (
        your_statement,
        even_more_statement = just_add_comma,
        return_value);}

http://www.cplusplus.com/doc/tutorial/operators/#comma


4
逗号是令人反感的运算符。它使那些不知道其存在或优先级的人感到困惑。imo永远不会有效使用。总是可以通过使用更多功能或更好地组织代码来避免这种情况。
jheriko

@jheriko同意,存在我的答案仅适用于那些真正想要独立的单线解决方案XD的人(它仍然是一行,对吗?)。逗号实际上并不引人注意,而且没人会以这种形式使用整个主要方法。
Valen

1
当然,您肯定给出了正确的答案,我只是不喜欢做任何鼓励或什至表现不好的作法。一旦人们知道逗号是一个运算符,就开始倒计时,直到他们开始滥用它为止;再倒一次,直到他们学到更好为止。:)
jheriko '16

@jheriko我已经看到它曾经在成员初始化列表中得到过有趣的使用,但是,如果我没记错的话,那只是为了弄乱。
贾斯汀时间-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.