Использование лямбда-функций C ++ во время инициализации переменных - PullRequest
7 голосов
/ 09 августа 2010

Я думаю, что у многих из вас где-то есть такой код:

int foo;
switch (bar) {
  case SOMETHING: foo = 5;  break;
  case STHNELSE:  foo = 10; break;
  ...
}

Но у этого кода есть некоторые недостатки:

  • Вы можете легко забыть "перерыв"
  • Переменная foo не является константой, в то время как она должна быть
  • Это просто не красиво

Так что я начал задаваться вопросом, существует ли способ «улучшить» этот видкода, и я получил эту небольшую идею:

const int foo = [&]() -> int {
  switch (bar) {
    case SOMETHING: return 5;
    case STHNELSE:  return 10;
    ...
  }
}();

Примечание: первая пара скобок это не обязательно, но MSVC ++ пока не поддерживает это

Вы можете использовать тот же прием с if-else, когда троичный оператор будет слишком сложным, переменные, которые должны быть переданы указателями для инициализации (например, для функций DirectX), и т. Д.

Мои вопросы:

  • Что-то не так с этим кодом, которого я не видел?
  • Считаете ли вы его лучше, чем приведенный выше?
  • g ++, кажется, встроен в функцию, но вы думаете, что все компиляторы будут делать это?

РЕДАКТИРОВАТЬ: это то, что я имею в виду под «функциями DirectX»

_xAudio2 = [&]() -> std::shared_ptr<IXAudio2> {
    IXAudio2* ptr = nullptr;
    if (FAILED(XAudio2Create(&ptr, xAudioFlags, XAUDIO2_DEFAULT_PROCESSOR)))
        throw std::runtime_error("XAudio2Create failed");
    return std::shared_ptr<IXAudio2>(ptr, [](IUnknown* ptr) { ptr->Release(); });
}();

Ответы [ 2 ]

3 голосов
/ 09 августа 2010

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

В JavaScript это основа "шаблона модуля", например

var myModule = (function() {

    // declare variables and functions (which will be "private")

    return {
       // populate this object literal with "public" functions
    };

})();

Таким образом, анонимная функция объявляется и немедленно вызывается, так что любые внутренние детали скрыты, и только возвращаемое значение отображается снаружи.

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

В императивном языке, таком как C ++, есть много языковых функций, которые выиграли бы от возможности возвращать значение (вместо того, чтобы быть похожими на void функцию). Например, if имеет альтернативу, третичный оператор expr ? a : b.

В Ruby практически все операторы могут быть оценены, поэтому нет необходимости в отдельном синтаксисе, в котором можно указать возвращаемое значение. Если бы C ++ работал таким образом, это означало бы что-то вроде:

auto result = try
{
    getIntegerSomehow();
}
catch (const SomeException &)
{
    0;
}
0 голосов
/ 09 августа 2010

Я не вижу никакой причины использовать корпус переключателя в таком случае. Любой приличный компилятор будет генерировать такой же быстрый код с операторами if, как и с переключателем.

if(bar == SOMETHING)
   foo = 5;
else if(bar == STHNELSE)
   foo = 10;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...