Явний тип повернення лямбди


93

Коли я намагаюся скомпілювати цей код (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

2
[&expression, &start, &end, &what, &flags]...(твій) проти [&]...(мій). А тепер скажи мені, чий є більш багатослівним. ;) [&]вказує лямбда-сигналу захоплювати все, що ви використовуєте всередині лямбда-тіла, шляхом посилання. Це називається "типовим захопленням". Інший є [=]і буде зафіксований за допомогою копії.
Xeo

1
@Xeo, Effective Modern C ++, Пункт 31, рекомендує робити явне захоплення, щоб уникнути звисання посилань. Мене це кілька разів вкусило як покарання за те, що я гультай ... е-е, лаконічний. :-)
Еміль Корм'є

2
До речі, обмеження зменшуються на виведені лямбди поверненого типу в C ++ 14. Типи повернення можуть бути виведені для лямбда з кількома операторами в тілі, і поки вираз кожного оператора return має однаковий тип, тепер можна мати виведений тип повернення з кількома операторами повернення.
Ентоні Холл,

Відповіді:


192

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

[]() -> Type { }

Однак, якщо лямбда має один оператор, і цей оператор є оператором return (і він повертає вираз), компілятор може вивести тип повернення з типу цього повернутого виразу. У вашій лямбда-команді є кілька висловлювань, тому вона не виводить тип.


4
компілятор може це робити, але стандарт забороняє це робити.
Йоханнес Шауб - літ

9
-1: Це не помилка компілятора. Щодо цього стандарт дуже чіткий: у пункті 4 розділу 5.1.2 викладено, як здійснюється відрахування та за яких умов.
Нікол Болас

2
Хоча це не дозволено відповідно до останнього проекту, я міг виявити, схоже, це насправді дозволено в остаточних специфікаціях, що йдуть за коментарем до цього виправлення gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . Хтось має остаточну специфікацію для перевірки?
Eelke

2
Я широко використовував лямбда-вирази і жодного разу явно не вказав тип return. Відрахування типу return (принаймні за VS2012 та VS2013) працює бездоганно, навіть якщо у виразі лямбда є більше одного оператора return. Звичайно, різні оператори return повинні збігатися в межах одного і того ж лямбда-виразу. Наприклад, такий вираз, як "auto f = [] (int i) {if (i> 5) return true; return false;};" компілюється без проблем, і якщо ви викликаєте "auto b = f (10);" b буде типу bool і, звичайно, буде правдою;
спрайт

1
return nullptr;може кинути гайковий ключ у вирахуванні типу, хоча він дійсний як будь-який тип вказівника, що повертається в іншому випадку.
Граулт

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

Але насправді, ваш другий вираз набагато читабельніший.


Гарний приклад; 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 (це все одно рядок, так?). Кома насправді не помітна, і ніхто ніколи не став би весь основний метод у цій формі.
Вален

1
звичайно, ви, звичайно, даєте слушну відповідь, я просто не прихильник того, щоб коли-небудь робити щось, щоб заохотити або навіть продемонструвати погану практику. як тільки люди дізнаються, що кома - це оператор, це відлік часу, доки вони не почнуть зловживати нею, і довший, поки вони не навчаться краще. :)
jheriko

@jheriko Я бачив, як це було цікаво використано в списку ініціалізації учасників одного разу, але це було лише для того, щоб возитися, якщо я правильно пам'ятаю.
Джастін Тайм - відновити Моніку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.