Это допустимое (ab) использование лямбда-выражений? - PullRequest
14 голосов
/ 21 мая 2011

Как мы все знаем, это не так просто break из вложенного цикла из внешнего цикла без:

  • a goto ( Пример кода. )
  • другая проверка состояния во внешнем цикле ( Пример кода. )
  • , помещая оба цикла в дополнительную функцию и возвращая вместо break ing (* 1015)* Пример кода. )

Хотя, ты должен признать, что все это довольно неуклюже.В частности, отсутствует версия функции из-за отсутствия контекста, в котором вызываются циклы, так как вам нужно передать все необходимое в циклах в качестве параметров.
Кроме того, второй ухудшается для каждого вложенного цикла.
Итак, я лично все еще считаю версию goto самой чистой.


Теперь, думая обо всем C ++ 0x и прочем, третий вариант принес мне эту идею, используя лямбда-выражения:

#include <iostream>

bool CheckCondition(){
  return true;
}

bool CheckOtherCondition(){
  return false;
}

int main(){
  [&]{while(CheckCondition()){
    for(;;){
      if(!CheckOtherCondition())
        return;
      // do stuff...
    }
    // do stuff...
  }}();
  std::cout << "yep, broke out of it\n";
}

( Пример в Ideone. )

Это обеспечивает семантическую красоту простого return, который предлагает третий вариант, не страдая от проблем контекста ибудучи (почти) столь же чистым как версия goto.Это также даже короче (по характеру), чем любой из вышеперечисленных вариантов.


Теперь я научился сдерживать свою радость после нахождения прекрасного (ab) использования языка, потому что есть почтивсегда какой-то недостаток.Есть ли на этом?Или есть даже лучший подход к проблеме?

Ответы [ 4 ]

16 голосов
/ 21 мая 2011

Пожалуйста, не делайте этого в проекте, которым я управляю. На мой взгляд, это нелепое злоупотребление лямбдами.

Используйте goto, где goto полезно.

4 голосов
/ 21 мая 2011

Каким образом это улучшение по сравнению с

void frgleTheBrgls()
{
  while(CheckCondition()) {
    for(;;) {
      if(!CheckOtherCondition())
        return;
      // do stuff...
    }
    // do stuff...
  }
}

int main()
{
  frgleTheBrgls();
  std::cout << "yep, broke out of it\n";
}

Это хорошо известно (функции, как вы знаете, как в BASIC), яснее (у алгоритма есть хорошее имя, объясняющее, что он делает)и делает точно так же, как ваш.

Особенно не хватает версии функции из-за отсутствия контекста, в котором вызываются циклы, так как вам нужно передать все необходимое в циклах в качестве параметров.

Я вижу это как преимущество.Вы видите именно то, что нужно, чтобы опрокинуть BRGLS.Простота при программировании часто является хорошей вещью.

4 голосов
/ 21 мая 2011

Совершенно верно, на мой взгляд. Хотя я предпочитаю присваивать мои имена, делая код более самодокументированным, т.е.

int main(){

  auto DoThatOneThing = [&]{while(CheckCondition()){
    for(;;){
      if(!CheckOtherCondition())
        return;
      // do stuff...
    }
    // do stuff...
  }};

  DoThatOneThing();
  std::cout << "yep, broke out of it\n";
}
1 голос
/ 02 октября 2011

Один недостаток с вашим предложенным синтаксисом: вы не можете иметь более 2 вложенных циклов. Синтаксис goto позволяет это:

int main()
{
    for (;;)
    {
        for (;;)
        {
            for (;;)
            {
                if (CheckCondition1()) goto BREAK_ON_COND1;
                if (CheckCondition2()) goto BREAK_ON_COND2;
                if (CheckCondition3()) break;
                // Do stuff when all conditions are false
            }
            // Do stuff when condition 3 becomes true
        }
    BREAK_ON_COND2:
        // Do stuff when condition 2 becomes true
    }
BREAK_ON_COND1: // When condition 1 becomes true
    std::cout << "yep, broke out of it\n";
}
...