Как сразу вызвать лямбду C++?

конструктор из класса, который я наследую, требует передачи нетривиального объекта. Похожие на это:

MyFoo::MyFoo() : SomeBase( complexstuff )
{
    return;
}

на complexstuff имеет мало общего с MyFoo, поэтому я не хотел его передавать.

вместо того, чтобы писать какую-то временную функцию 1-off, которая возвращает complexstuff я использовал лямбда. Мне потребовалось несколько минут, чтобы понять, что я должен invoke лямбда. Так что мой код теперь выглядит так это:

MyFoo::MyFoo() : SomeBase(
    []()
    {
        /* blah blah do stuff with complexstuff */
        return complexstuff;
    } () )
{
    return;
}

если вы не поймали его, это тонко. Но после лямбда-тела мне пришлось положить () чтобы сообщить компилятору немедленно "запустить" лямбду. Что имело смысл после того, как я поняла, что сделала не так. В противном случае, без () чтобы вызвать лямбду, gcc говорит что-то подобное этому:

error: no matching function for call to 'SomeBase(<lambda()>)'

но теперь, я думаю ... я сделал это правильно? Есть ли лучший способ В C++11 или C++14 сказать компилятору, что я хочу немедленно вызвать лямбду, которую я написал? Или добавляет пустой () как я сделал обычный способ сделать это?

4 ответов


но теперь, я думаю ... я сделал это правильно?

да.

есть ли лучший способ В C++11 или C++14 сообщить компилятору, что я хочу, чтобы он немедленно вызвал лямбду, которую я написал?

насколько мне известно, нет. Лямбда-это также просто объект функции, поэтому вы нужно иметь () чтобы вызвать его, нет никакого способа обойти его (за исключением, конечно, некоторой функции, которая вызывает лямбда как std::invoke).

если вы хотите, вы можете отбросить () после списка захвата, потому что твоя лямбда не принимает никаких параметров.

или добавляет пустой () Как я сделал обычный способ сделать это?

Да, это самый короткий путь. Как уже говорилось,std::invoke также будет работать вместо этого, но для этого требуется больше ввода. Я бы сказал, прямой звонок с () Это обычный способ, которым это делается.


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

Если вы хотите избежать синтаксиса, то либо измените SomeBase или complexstuff для выполнения отзывной.


Если все, что вы хотите-это синтаксический сахар для вызова лямбда, вы всегда можете сделать то, что делает что-то вроде SCOPE_GUARD Александреску, и злоупотреблять перегрузкой оператора:

видео

#include <iostream>

constexpr enum {} invoke{};

template<class Callable>
auto operator+(decltype(invoke) const&, Callable c) -> decltype(c()) {
    return c();
}


int main() {
    invoke + []() {
        std::cout << "called";
    };
}

но я бы не стал. Изобретение собственного DSL просто сделает ваш код хуже для поддержания. Придерживайтесь идиом, которые используют простые языковые конструкции.


В C++17 вы можете использовать std::invoke. Это делает то же самое, что и вы, но, возможно, вы найдете это более ясным.

#include <iostream>
#include <functional>

void foo(int i)
{
  std::cout << i << '\n';
}

int main()
{
  foo( std::invoke( []() { return 1; } ) );
}

есть ли лучший способ

вы также можете рассмотреть возможность создания частной статической функции-члена complexstuff, что-то вроде

class MyFoo : public Base {
private:
    static SomeComplexType compute_complex_stuff() {
      SomeComplexType complexstuff;
      /*compute the complexstuff */
      return complexstuff;
    };
public: 
    MyFoo() : Base(compute_complex_stuff()) {};
};

Я не знаю, лучше ли это, чем определить лямбда-выражение и применить его немедленно; это ИМХО вопрос вкуса; для short лямбда-тело я бы предпочел, чтобы лямбда-выражение немедленно применялось (но, возможно, какой-то компилятор создал бы временное закрытие в этом случае, поэтому это может быть медленнее без оптимизации; я ожидаю, что большинство компиляторов C++11 смогут сделать эту оптимизацию).

кстати, GCC предоставляет выражение расширение языка (также понимается Clang) для ваших целей. С его помощью вы могли бы написать

MyFoo::MyFoo : Base (({
  SomeComplexType complexstuff;
  /*compute the complexstuff */
  return complexstuff;
}) {};