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

94

Когда я пытаюсь скомпилировать этот код (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); }));
}
Райан
источник
6
Вы можете явно указать это с помощью ->, например[&](double d) -> double { //...
Flexo
2
Я бы посоветовал вам просто неявно фиксировать нужные вам переменные (только [&]...), поскольку то, что у вас есть в настоящее время, излишне многословно.
Xeo 08
2
[&expression, &start, &end, &what, &flags]...(твое) против [&]...(мое). А теперь скажите, чей из них более подробный. ;) [&]указывает лямбда-выражению захватывать все, что вы используете внутри тела лямбда-выражения, по ссылке. Это называется «захват по умолчанию». Другой - [=]и будет копировать.
Xeo
1
@Xeo, Эффективный современный C ++, пункт 31, рекомендует явно осуществлять захват, чтобы избежать висящих ссылок. Меня это несколько раз укусило в наказание за ленивость ... э-э, лаконичность. :-)
Эмиль Кормье
2
Кстати, ограничения на выведенные лямбды возвращаемого типа в C ++ 14 уменьшены. Типы возвращаемых значений могут быть выведены для лямбда-выражений с более чем одним оператором в теле, и пока выражение каждого оператора возврата имеет один и тот же тип, теперь вы можете получить выведенный тип возвращаемого значения с несколькими операторами возврата.
Энтони Холл

Ответы:

195

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

[]() -> Type { }

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

Сет Карнеги
источник
4
компилятор может это сделать, но стандарт запрещает это делать.
Йоханнес Шауб - лит
10
-1: это не ошибка компилятора. В стандарте это очень четко прописано: параграф 4 раздела 5.1.2 описывает, как производится вычет и на каких условиях.
Никол Болас
2
Хотя это не разрешено в соответствии с последним проектом, я обнаружил, что похоже, что это действительно разрешено в окончательных спецификациях в комментарии к этому патчу gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . У кого-нибудь есть окончательная спецификация для проверки?
Eelke 01
2
Я широко использовал лямбда-выражения и ни разу не указывал явно возвращаемый тип. Выведение типа возвращаемого значения (по крайней мере, в VS2012 и VS2013) работает безупречно, даже если в лямбда-выражении содержится более одного оператора возврата. Конечно, различные операторы возврата должны соответствовать одному и тому же лямбда-выражению. Например, такой оператор, как «auto f = [] (int i) {if (i> 5) return true; return false;};» компилируется без проблем, и если вы вызываете "auto b = f (10);" b будет иметь тип bool и, конечно, будет истинным;
спрайт
1
return nullptr;может бросить вызов при выводе типа, даже если он действителен, как и любой другой тип указателя, возвращаемый в противном случае.
Grault
16

Тип возвращаемого лямбда- выражения (в 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;
  })

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

Никол Болас
источник
Хороший пример; придирка: Ваш вызов функции отсутствует );в конце?
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 (это все еще одна строка, верно?). Запятая действительно не заметна, да и весь основной метод в таком виде никто бы никогда не поместил.
Вален
1
Конечно, вы даете правильный ответ, я просто не сторонник того, чтобы когда-либо делать что-либо, чтобы поощрять или даже демонстрировать плохую практику. как только люди узнают, что запятая - это оператор, это обратный отсчет, пока они не начнут злоупотреблять ею, и более длинный, пока они не научатся лучше. :)
jheriko
@jheriko Однажды я видел, как это интересно использовалось в списке инициализации участников, но это было просто для того, чтобы возиться, если я правильно помню.
Джастин Тайм - Восстановить Монику