Явный тип возврата лямбды

Когда я пытаюсь скомпилировать этот код (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;
  });
}

Как я указал, что лямбда имеет возвращаемый тип void. Более того, как мне указать, что лямбда имеет возвращаемый тип 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); }));
}

person Ryan    schedule 08.03.2012    source источник
comment
Вы можете явно указать это с помощью ->, например [&](double d) -> double { //...   -  person Flexo    schedule 08.03.2012
comment
Я бы посоветовал вам просто неявно фиксировать нужные вам переменные (только [&]...), так как то, что у вас есть в настоящее время, излишне многословно.   -  person Xeo    schedule 09.03.2012
comment
@Xeo, можешь мне сказать, почему он многословен? Мне нужно что, выражение и флаги в лямбде, и это то, что я уловил. Какое моё я мог вырезать?   -  person Ryan    schedule 12.03.2012
comment
[&expression, &start, &end, &what, &flags]... (ваш) vs [&]... (мой). А теперь скажите, чей из них более подробный. ;) [&] сообщает лямбда-выражению о необходимости захвата всего, что вы используете внутри тела лямбда-выражения, по ссылке. Это называется захватом по умолчанию. Другой - [=] и будет записан копией.   -  person Xeo    schedule 12.03.2012
comment
@Xeo, Эффективный современный C ++, пункт 31, рекомендует явно захватывать, чтобы избежать висящих ссылок. Меня это несколько раз укусило в наказание за ленивость ... э-э, лаконичность. :-)   -  person Emile Cormier    schedule 19.01.2016
comment
@Emile: На самом деле это имеет значение только для лямбда-выражений, которые в той или иной форме переживают текущую область видимости, что, конечно же, здесь не так.   -  person Xeo    schedule 21.01.2016
comment
Кстати, ограничения на выведенные лямбды возвращаемого типа в C ++ 14 уменьшены. Типы возвращаемых значений могут быть выведены для лямбда-выражений с более чем одним оператором в теле, и до тех пор, пока выражение каждого оператора возврата имеет один и тот же тип, теперь вы можете иметь выводимый тип возвращаемого значения с несколькими операторами возврата.   -  person Anthony Hall    schedule 18.06.2016


Ответы (3)


Вы можете явно указать тип возвращаемого значения лямбда, используя -> Type после списка аргументов:

[]() -> Type { }

Однако, если лямбда-выражение имеет один оператор и этот оператор является оператором возврата (и возвращает выражение), компилятор может вывести тип возвращаемого значения из типа этого одного возвращенного выражения. У вас есть несколько операторов в лямбде, поэтому он не определяет тип.

person Seth Carnegie    schedule 08.03.2012
comment
компилятор может это сделать, но стандарт запрещает это делать. - person Johannes Schaub - litb; 08.03.2012
comment
-1: это не ошибка компилятора. В стандарте это очень ясно: в параграфе 4 раздела 5.1.2 излагается, как производится вычет и на каких условиях. - person Nicol Bolas; 08.03.2012
comment
Хотя это не разрешено в соответствии с последним проектом, я обнаружил, что похоже, что это действительно разрешено в окончательных спецификациях, указанных в комментарии к этому патчу gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html. У кого-нибудь есть окончательная спецификация для проверки? - person Eelke; 01.08.2013
comment
Я широко использовал лямбда-выражения и ни разу не указывал явно возвращаемый тип. Выведение типа возвращаемого значения (по крайней мере, в VS2012 и VS2013) работает безупречно, даже если в лямбда-выражении содержится более одного оператора возврата. Конечно, различные операторы возврата должны соответствовать одному и тому же лямбда-выражению. Например. такой оператор, как auto f = [] (int i) {if (i ›5) return true; вернуть ложь; }; компилируется без проблем, и если вы вызываете auto b = f (10); b будет иметь тип bool и, конечно же, будет истинным; - person sprite; 02.03.2015
comment
return nullptr; может помешать выведению типа, даже если он действителен, как и любой другой тип указателя, возвращаемый в противном случае. - person Grault; 11.04.2015
comment
return ptr; может также помешать вычету типа, если задействован const. - person wcochran; 12.03.2018

Тип возвращаемого лямбда-выражения (в C ++ 11) можно вывести, но только, когда есть ровно один оператор, и этот оператор является оператором return, который возвращает выражение (список инициализаторов не выражение, например). Если у вас есть лямбда с несколькими операторами, предполагается, что возвращаемый тип недействителен.

Следовательно, вам следует сделать так:

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

Но на самом деле ваше второе выражение намного читабельнее.

person Nicol Bolas    schedule 08.03.2012
comment
Хороший пример; придирка: В конце вашего вызова функции отсутствует );? - person kevinarpe; 11.03.2017

Когда вы все еще возвращаетесь, у вас может быть более одного оператора:

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

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

person Valen    schedule 27.09.2014
comment
запятая - отвратительный оператор. это сбивает с толку людей, которые не знают о его существовании или уровне приоритета. там никогда не будет действительного использования imo. его всегда можно избежать с помощью большего количества функций или иным образом лучше организованного кода. - person jheriko; 21.01.2016
comment
@jheriko согласен, мой ответ существует только для тех, кто действительно хочет независимое однострочное решение XD (это все еще одна строка, верно?). Запятая действительно не заметна, да и весь основной метод в такую ​​форму никто бы никогда не поместил. - person Valen; 10.04.2016
comment
Конечно, вы определенно даете правильный ответ, я просто не поклонник того, чтобы когда-либо делать что-либо, чтобы поощрять или даже демонстрировать плохую практику. как только люди узнают, что запятая - это оператор, начнется обратный отсчет, пока они не начнут злоупотреблять ею, и более длинный, пока они не научатся лучше. :) - person jheriko; 04.05.2016
comment
@jheriko Однажды я видел, как это интересно использовалось в списке инициализации участников, но это было просто для того, чтобы возиться, если я правильно помню. - person Justin Time - Reinstate Monica; 15.12.2016
comment
Ах, но какой читатель хотя бы сначала не взглянул, чтобы увидеть, можно ли перегрузить оператор запятой. Что же это будет за великое зло? - person TJ Bandrowsky; 19.04.2021