Explicit Return Type of Lambda

134,846

Solution 1

You can explicitly specify the return type of a lambda by using -> Type after the arguments list:

[]() -> Type { }

However, if a lambda has one statement and that statement is a return statement (and it returns an expression), the compiler can deduce the return type from the type of that one returned expression. You have multiple statements in your lambda, so it doesn't deduce the type.

Solution 2

The return type of a lambda (in C++11) can be deduced, but only when there is exactly one statement, and that statement is a return statement that returns an expression (an initializer list is not an expression, for example). If you have a multi-statement lambda, then the return type is assumed to be void.

Therefore, you should do this:

  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;
  })

But really, your second expression is a lot more readable.

Solution 3

You can have more than one statement when still return:

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

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

Share:
134,846

Related videos on Youtube

Ryan
Author by

Ryan

Software developer interested in Swift and Typescript.

Updated on September 15, 2020

Comments

  • Ryan
    Ryan over 3 years

    When I try and compile this code (VS2010) I am getting the following error: 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;
      });
    }
    

    How did I specify that the lambda has a 'void' return type. More-over, how do I specify that the lambda has 'bool' return type?

    UPDATE

    The following compiles. Can someone please tell me why that compiles and the other does not?

    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); }));
    }
    
    • Flexo
      Flexo about 12 years
      You can explicitly specify it with ->, e.g. [&](double d) -> double { //...
    • Xeo
      Xeo about 12 years
      I'd advise you to just implicitly capture the variables you need (only [&]...), as what you currently have is needlessly verbose.
    • Ryan
      Ryan about 12 years
      @Xeo can you tell me why its verbose? I need what, expression and flags in the lambda and that is what I have captured. What mroe could I cut out?
    • Xeo
      Xeo about 12 years
      [&expression, &start, &end, &what, &flags]... (yours) vs [&]... (mine). Now tell me whose is more verbose. ;) [&] tells the lambda to capture everything that you use inside the lambda body, by reference. It's called a "capture default". The other one is [=] and will capture by copy.
    • Emile Cormier
      Emile Cormier over 8 years
      @Xeo, Effective Modern C++, Item 31, recommends capturing explicitly, to avoid dangling references. I've been bitten by that a few times myself as punishment for being laz... er, concise. :-)
    • Xeo
      Xeo over 8 years
      @Emile: That only matters for lambdas that outlive the current scope in some form or other, really, which is certainly not the case here.
    • Anthony Hall
      Anthony Hall almost 8 years
      By the way, the constraints are reduced on deduced return-type lambdas in C++14. Return types can be deduced for lambdas with more than one statement in the body, and as long as the expression of each return statement has the same type, you can now have a deduced return type with multiple return statements.
    • jww
      jww over 7 years
  • Johannes Schaub - litb
    Johannes Schaub - litb about 12 years
    the compiler can do that, but the standard forbids it to do that.
  • Nicol Bolas
    Nicol Bolas about 12 years
    -1: This is not a compiler bug. The standard is very clear on this: section 5.1.2, paragraph 4 lays out how the deduction is made and under what conditions it is.
  • Eelke
    Eelke almost 11 years
    While it is not allowed according to the latest draft I could find it looks like it is actually allowed in the final specs going by the comment for this patch gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html. Anyone has the final spec to verify?
  • sprite
    sprite about 9 years
    I've used lambda expressions extensively and not once did I explicitly state the return type. The deduction of the return type (at least under VS2012 & VS2013) works flawlessly even if there's more than one return statement in the lambda expression. Of course, the various return statements need to match within the same lambda expression. E.g. a statement such as "auto f = [](int i) { if(i > 5) return true; return false; };" compiles with no problem and if you call "auto b = f(10);" b will be of type bool and of course be true;
  • Grault
    Grault about 9 years
    return nullptr; can throw a wrench in the type deduction, even though it's valid as whatever pointer type is otherwise returned.
  • jheriko
    jheriko over 8 years
    comma is a revolting operator. its confuses people who aren't aware of its existence or precedence level. there is never a valid use either imo. it can always be avoided with more functions or otherwise better organised code.
  • Valen
    Valen about 8 years
    @jheriko agree, the existence of my answer is only for those who really wants a independent one-liner solution XD (it's still one line, right?). The comma is really not noticeable, and no one would ever put the whole main method in this form.
  • jheriko
    jheriko about 8 years
    sure, you are certainly giving a valid answer, i am just not a fan of ever doing anything to encourage or even demonstrate bad practice. once people learn that comma is an operator its a countdown until they start abusing it and a longer one until they learn better. :)
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    @jheriko I've seen it put to an interesting use in a member initialisation list once, but that was just for messing around, if I remember correctly.
  • kevinarpe
    kevinarpe about 7 years
    Nice example; nitpick: Is your function call missing ); at the end?
  • wcochran
    wcochran about 6 years
    return ptr; can also throw a wrench in type deduction if const is involved.
  • TJ Bandrowsky
    TJ Bandrowsky about 3 years
    Ah, but what reader did not at least first look to see if the comma operator was something you could overload. Now what great evil would that be?