Это технически решает вашу проблему:
std::function<void()> func = [&func]{
std::cout << "a\n";
func = []{ std::cout << "b\n"; };
};
Но это не очень хороший план.Время жизни и поведение функции std связано с локальной переменной стека.Копии не в состоянии выполнить то, что вы, вероятно, хотите почти в любом смысле - они продолжают печатать "a\b"
, если они не пересекаются с ошибкой, потому что оригинал func
выпал из области видимости.
Чтобы исправить это, мы должныразвернуть несколько больших орудий;для начала Королева функционального программирования г-жа Y Combinator:
std::function<void()> func = y_combinate( [](auto&& self){
std::cout << "a\n";
self = []{ std::cout << "b\"; };
} );
Y Combinator принимает функцию сигнатуры F = (F,Args...)->R
, а затем возвращает функцию сигнатуры (Args...)->R
.Вот как языки без состояний управляют рекурсией, когда вы не можете назвать себя, пока не получили имя.
Написание Y-комбинатора проще, чем вы опасаетесь в C ++:
template<class F>
struct y_combinator_t {
F f;
template<class...Args>
auto operator()(Args&&...args)
-> typename std::result_of< F&( F&, Args&&... ) >::type
{
return f( f, std::forward<Args>(args)... );
}
};
template<class F>
y_combinator_t<typename std::decay<F>::type> y_combinate( F&& f ) {
return {std::forward<F>(f)};
}
к сожалению, это не такне работает, поскольку тип self
, передаваемый лямбде, на самом деле является типом оригинальной лямбды.И лямбда с b-печатью - это не связанный тип.Поэтому, когда вы пытаетесь self = []{ std::cout << "b\n"; }
, вы получаете ошибку, встроенную в некоторые относительно глубокие ошибки спама в шаблонах.
Sad;но только временная задержка.
Нам нужен тип, который очень трудно назвать - F = std::function<void(F)>
- std::function
, который принимает в качестве одного аргумента экземпляр объекта того же типа.
Обычно это невозможно сделать, но с небольшим количеством шаблонного дурачества ... Здесь я сделал это раньше.
Тогда ваш код читает:
std::function<void()> func = y_combinate( recursive_func< void(own_type&) >([](auto&& self){
std::cout << "a\n";
self = [](auto&&){ std::cout << "b\n"; };
}) );
и при вызове данной копии func
сначала печатается "a\n"
, затем при каждом последующем вызове печатается "b\n"
.Копии b-принтеров также печатают b, но копии a-принтеров будут печататься в первый раз перед переходом.
Живой пример .
self
в этомкод recursive_func< void(own_type&) >
, поэтому вы можете сделать то же самое в b-принтере, как и в a-принтере.