Я читаю такой код на С++:
const auto candidate_path = std::invoke([&]() {
if (status == ModuleStatus::SUCCESS || status == ModuleStatus::FAILURE) {
// clear candidate path if the module is finished
return convertToPath(nullptr, false, planner_data);
}
return convertToPath(
observer.lock()->getPathCandidate(), observer.lock()->isExecutionReady(), planner_data);
});
Код создает анонимную функцию и захватывает все по ссылке [&](){}
, а затем вызывает ее std::invoke()
. Я хотел бы посмотреть, есть ли от этого какая-нибудь польза?
Спасибо.
candidate_path
может быть константой
Он действительно создает область видимости, которая связана с внешним миром одним оператором возврата. В основном это делается для управления исходной мутацией и вспомогательными материалами для возвращаемого объекта. Иногда его используют для обхода недостатков конструкторов.
Переменная candidate_path
должна быть const
-квалифицированной. Немедленно вызываемая лямбда позволяет использовать (несколько) операторов для инициализации переменной, а не просто одно выражение после =
, не жертвуя const
.
В этом конкретном случае это сработало бы и с использованием тернарного оператора в одном выражении, но это может быть сложнее читать.
Причина использования std::invoke
для вызова лямбды вместо записи [&](){ /*...*/ }()
, вероятно, связана с личными предпочтениями автора. Возможная причина, которую я вижу, заключается в том, что легче распознать вызов лямбды. При использовании синтаксиса прямого вызова функции можно легко пропустить ()
в конце.
Предназначена ли функция lamda/std::invoke для инициализации const
? Я должен сказать, что C++ сложен, некоторые побочные эффекты используются как обычная практика (или даже общие шаблоны).
@FelixFXu Нет, лямбды в гораздо большей степени полезны как более простая альтернатива определяемым пользователем классам в качестве функциональных объектов, когда вы хотите передать «функцию» с состоянием другой функции. Фактическая цель std::invoke
— унифицировать различный синтаксис «вызова» для разных типов объектов, например, чтобы иметь возможность обрабатывать указатели на функции-члены, которые в противном случае нужно было бы вызывать как obj.*mptr()
так же, как вызов функции, принимающий объект в качестве дополнительного первого аргумента. : std::invoke(mptr, obj);
. Это полезно при общем программировании с использованием шаблонов.
@FelixFXu Я не знаю, что вы имеете в виду под побочными эффектами, но используемый здесь шаблон имеет целью уменьшить возможные побочные эффекты, гарантируя наличие только const
переменных. По сути, это что-то вроде импровизированного стиля функционального программирования.
@FelixFXu Лямбды в целом важны, и каждый, кто пишет на C++, должен их знать. Немедленно вызываемый лямбда-шаблон не так уж важен и поначалу может показаться запутанным, но станет естественным и очевидным, как только вы увидите/используете его несколько раз. std::invoke
— это не то, что обычно нужно знать пользователям C++. Это актуально только для авторов библиотек, которым необходимо, чтобы функциональность их библиотеки была как можно более универсальной. Для используемого здесь шаблона он не нужен, и я не часто вижу, чтобы он использовался таким образом.
@FelixFXu Кроме того, если вы еще новичок в C++, код, который вы показываете, явно написан кем-то со значительным опытом. Он также использует другие неочевидные шаблоны, например, способ использования блокировки. К сожалению, C++ слишком сложен, чтобы можно было понять код, написанный опытным пользователем, использующим множество его функций, имея лишь базовое понимание языка. Учиться нужно маленькими шагами.
Это похоже на вопрос типа списка. Вопрос в виде списка не по теме/не по теме?