Является ли это допустимым (ab) использованием лямбда-выражений?

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

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


Теперь, думая все С++ 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) использование языка, потому что почти всегда есть какой-то недостаток. Есть ли что-нибудь на этом? Или есть даже лучший подход к проблеме?

Ответ 1

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

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

Ответ 2

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

int main(){

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

  DoThatOneThing();
  std::cout << "yep, broke out of it\n";
}

Ответ 3

В каком смысле это улучшение над

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

Один из недостатков вашего предложенного синтаксиса: вы не можете иметь более двух вложенных циклов. Синтаксис '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";
}