Инициализация один раз с указателем на лямбда-функцию, самоизменение (C ++) - PullRequest
0 голосов
/ 18 февраля 2020

Мне было интересно, возможно ли создать встроенную функцию лямбда-инициализации, поэтому после инициализации она заменит себя фиктивной инициализацией. Какой-то ленивый алгоритм инициализации с минимально возможной болью. Вот некоторый псевдокод, которого я хотел бы достичь:

SomeData* data = nullptr;
auto initF = [&]
{
    data = initData();
    initF = [&] {};
};

, поэтому для l oop это будет выглядеть так:

for(int i = 0; i < count; i++) {
     initF();
     data[i] = ....;
}

В основном, если count равен 0 - initF никогда не будет вызван, но однажды вызванный - указатель инициализируется и может использоваться после этого.

Ответы [ 2 ]

2 голосов
/ 18 февраля 2020

Ну, ваш код почти работает. * * * * * * * * * * * * * * * * * * * * * * * * *} * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} * * * * * * * * * * * * * * * * *}}}. исключите отдельное существование data, поэтому у вас есть только функция.

std::function<int&()> data = [&]() -> int& {
    return (data = [res = 5]() mutable -> int& { return res; })();
    //              ^^^ the variable becomes a "hidden" data member of the closure
}

Это исключает возможность случайного использования переменной перед вызовом инициализатора.

0 голосов
/ 18 февраля 2020

Используйте умный указатель для закрытия .

std::shared_ptr<std::function<void(void)>> initf;

Затем используйте std::call_once для его инициализации (с некоторыми лямбда-выражение ) или какой-либо конструктор stati c, инициализирующий его, например,

//untested
initf.reset (& [&] () { initf = [&]() {
   auto oldinitf=initf; static int cnt;
   cnt++;
   std::cout << "cnt=" << cnt << std::endl;
   if (oldinitf)
      (oldinitf.get()) ();
});

Читайте также о Y комбинаторе с фиксированной точкой в нетипизированном λ-исчисление .

Книга Куинны c Лисп в маленьких кусочках Теорема Райса ) связана с вашим вопросом.

Заметьте, что циклические ссылки в памяти требуют, по крайней мере, косвенного обращения (что недружественно к подсчету ссылок подходов).

На Linux вы можете сгенерировать некоторые аналогичный код C ++ во время выполнения (с использованием необработанных указателей на функции), скомпилируйте его во временный плагин, а затем используйте dlopen с dlsym (я делал это несколько лет go в G CC MELT , сейчас устарел). См. C ++ dlopen minihowto и посмотрите на RefPerSys в качестве примера (программы на C ++, генерирующей и выполняющей код C ++). Посмотрите также на JIT-компиляцию библиотек, таких как libgccjit , asmjit , et c ...

Обратите внимание, что такие трюки проще с SBCL , как только вы приложите усилия для изучения Common Lisp . SBCL генерирует машинный код не более REPL взаимодействий.

...