Означает ли это, что если у меня есть библиотечная функция, которая принимает произвольный аргумент функции и записывает его в лямбду, мне всегда нужно сделать эту лямбду непостоянной, потому что я не знаю, что могут передавать пользователи?
Это дизайнерское решение для API вашей библиотеки.Вы можете требовать, чтобы клиентский код передавал функциональные объекты с const
-квалифицированным operator()
(что имеет место для не mutable
лямбда-выражений).Если передается что-то другое, возникает ошибка компилятора.Но если для контекста может потребоваться аргумент объекта функции, который изменяет его состояние, тогда да, вы должны сделать внутреннюю лямбду mutable
.
. Альтернативой может быть отправка сообщения о способности вызывать operator()
вconst
-квалифицированный экземпляр данного типа функции.Что-то вроде этого (обратите внимание, что это требует исправления для функциональных объектов как с const
, так и не const
operator()
, что приводит к неоднозначности):
template <class Fct>
auto wrap(Fct&& f) -> decltype(f(), void())
{
[fct = std::forward<Fct>(f)]() mutable { fct(); }();
}
template <class Fct>
auto wrap(Fct&& f) -> decltype(std::declval<const Fct&>()(), void())
{
[fct = std::forward<Fct>(f)]() { fct(); }();
}
Примечательно,Обертывание f1 в std :: function, кажется, решает эту проблему (как?).
Это ошибка в std::function
из-за ее семантики стирания типа и копирования.Он позволяет вызывать не const
-квалифицированный operator()
, что можно проверить с помощью следующего фрагмента:
const std::function<void()> f = [i = 0]() mutable { ++i; };
f(); // Shouldn't be possible, but unfortunately, it is
Это известная проблема, ее стоит проверить Жалоба Тита Винтера на этом.