Domanda Chiama lambda ricorsiva in C ++ nella stessa riga in cui è dichiarata


Questo è per lo più un tipo di domanda di un solo liner, normalmente scriverei questo codice in più righe comunque per motivi di leggibilità.

Quindi la mia domanda è: posso chiamare il lambda ricorsivo nella stessa frase dove è definito?

Quindi, invece di questo:

int n=3;
function<void(int)> f {[n,&f](int i){if (i>1) { cout << "func(a, "; f(i-1); cout << ")";} else cout << "a";}};
f(n);

chiama la funzione con n nella stessa riga dove f è definito.


17
2018-03-14 21:16


origine


risposte:


Permettetemi di dare un'occhiata al mondo della programmazione funzionale, in cui le persone solitamente usano combinatori trattare con lambda ricorsivi. C'era un proposta (P0200r0) l'anno scorso per aggiungere un semplice combinatore Y alla libreria standard.

Lasciando da parte la domanda se sia una buona idea farlo, questo ti permetterebbe di scrivere e invocare un lambda ricorsivo come questo:

y_combinator([](auto self, int i){
    if (i>1) {
        std::cout << "func(a, ";
        self(i-1);
        std::cout << ")";
    } else {
        std::cout << "a";
    }
})(6);

L'idea di base qui è che il combinatore y è una funzione di ordine superiore che avvolge un lambda che viene passato 'se stesso' come primo argomento. Il combinatore si occupa di avvolgere l'argomento autonomo per tutte le invocazioni del lambda.

Puoi provalo in coliru.


6
2018-03-15 06:17



In una dichiarazione che dichiara diverse variabili ;-)
Per lo più non quello che vuoi:

std::function<void(int)>
    f {[&f](int i){
        if (i>1) {
            std::cout << "func(a, "; f(i-1); std::cout << ")";}
        else
            std::cout << "a";
    }},
    dummy((f(3), nullptr));

dimostrazione


14
2018-03-14 21:47



È un dato di fatto, puoi. Ecco un esempio completo che compila e funziona bene con g++ -std=c++11:

#include <iostream>
#include <functional>

int main() {
    std::function<int(int)> f = ([&f](int i){ return i?f(i-1)*i:1; }), trash = (std::cout << f(3) << std::endl, f);
}

Tuttavia, non penso che sia una buona idea usare effettivamente questo: il costrutto , trash = (..., f) sarebbe in ordine per il golf del codice o i concorsi di programmazione offuscati, ma non soddisferebbe i miei standard per il codice di produzione.


6
2018-03-14 21:58



Quello che stai essenzialmente chiedendo è creare un'istanza temporanea di std::function e quindi invocare operator() su quell'oggetto nella stessa dichiarazione. Entrambi non riescono a compilare per me lo stesso errore quando provo che:

function<void(int)> f{[&f](int i){ if (i > 1) { cout << "func(a, "; f(i-1); cout << ")"; } else cout << "a"; }}(n);

function<void(int)> f([&f](int i){ if (i > 1) { cout << "func(a, "; f(i-1); cout << ")"; } else cout << "a"; })(n);

errore: previsto ',' o ';' prima '(' token

Indicando il ( di (n).

Vedi la risposta di @ Jarod42 per una valida soluzione alternativa, se non ti interessa l'inizializzazione della variabile extra.

In alternativa, funzionerebbe, anche se deve utilizzare dichiarazioni e assegnazioni variabili separate:

function<void(int)> f; f = [&f](int i){ if (i > 1) { cout << "func(a, "; f(i-1); cout << ")"; } else cout << "a"; }, f(n);

dimostrazione


3
2018-03-14 21:47



Non sono sicuro se lo consideri valido dal momento che non usa le funzioni lambda, ma è ancora una linea singola e non lascia alcuna variabile temporale dietro)

struct {
  struct R {
    R(int i) {
      if (i>1) { cout << "func(a, "; R(i-1); cout << ")"; }
      else cout << "a";
    }
  } r;
} f{n};

2
2018-03-14 22:13