Как сразу вызвать лямбду 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;
}) {};