2013-03-11 6 views
7

Browsing einige Internet-Board Bindung traf ich diese kleine Herausforderung:Anruf Lambda ohne es auf eine Kennung

„Implementieren einer rekursiven anonyme Funktion in Ihrer bevorzugten Sprache“

Offensichtlich ist dies einfach ein mit std :: function/Funktionszeiger.

Was mich wirklich interessiert ist, wenn das möglich ist, ohne den Lambda an eine Kennung zu binden?

So etwas wie (die offensichtliche unendliche Rekursion zu ignorieren):

[](){ this(); }(); 
+1

Verwenden Sie den [Fixpunktkombinator] (http://stackoverflow.com/questions/152084/fixed-point-combinators-in-c) und Sie können jede Funktion in eine rekursive Funktion umwandeln. – didierc

+1

Wollte Sie keine Kennung, oder meinten Sie wirklich anonym?C++ kann nicht-anonyme Namen haben, die aus _ Bezeichnern bestehen, aber selbst keine Bezeichner sind. –

+0

Mit keinem Bezeichner meine ich keinen Variablennamen – user1233963

Antwort

5

Natürlich in C++, rufen jede Funktion können Sie es auf eine Kennung irgendwo zu binden zu nennen, einfach zu Syntax Zwänge zurückzuführen ist. Aber wenn Sie Parameter als ausreichend ungenannt akzeptieren, dann ist es möglich, eine Version des y-Kombinators in C++ zu erstellen, die gut rekursiert, ohne "benannt" zu sein.

Nun, das ist wirklich hässlich, weil ich nicht weiß, wie man eine typedef for a recursive lambda macht. Es benutzt also nur eine Menge Missbrauch. Aber es funktioniert, und druckt FLY!!, bis es wegen Stack-Überlauf segregiert.

#include <iostream> 

typedef void(*f0)(); 
typedef void(*f)(f0); 

int main() { 
    [](f x) { 
     x((f0)x); 
    } ([](f0 x) { 
     std::cout<<"FLY!!\n"; 
     ((f)x)(x); 
    }); 
} 

Die beiden Lambda-Ausdrücke sind im Sinne unbenannte, dass weder explizit Namen überall zugeordnet ist. Das zweite Lambda ist das eigentliche Arbeitspferd, und es nennt sich im Grunde genommen das erste Lambda, um sich in Form des Parameters auf sich selbst zu beziehen.

Hier ist, wie Sie diese nutzen würde etwas „nützlich“ zu tun:

#include <iostream> 

typedef int param_t; 
typedef int ret_t; 

typedef void(*f0)(); 
typedef ret_t(*f)(f0, param_t); 

int main() { 
    /* Compute factorial recursively */ 
    std::cout << [](f x, param_t y) { 
     return x((f0)x, y); 
    } ([](f0 x, param_t y) { 
     if(y == 0) 
      return 1; 
     return y*((f)x)(x, y-1); 
    }, 10) << std::endl; 
} 
+0

Warum der Downvote? Das ist schön! – user1233963

3

Sind Sie zu betrügen erlaubt?

void f(){ 
    []{ f(); }(); 
} 

Es ist rekursiv - indirekt, atleast.

Ansonsten, nein, es gibt keine Möglichkeit, auf das Lambda selbst zu verweisen, ohne ihm einen Namen zu geben.

+1

Interessante Problemumgehung, aber ein Funktionsname ist auch ein Bezeichner, oder? – user1233963

+2

@user: Sicher, aber die Frage verbot eine indirekte Rekursion nicht. :) – Xeo

+2

@Xeo: das ist gleichbedeutend mit 'void f() {f(); } ', wirklich ... – nneonneo

1

Keine Kennung für Funktionen/Methoden, Nah genug oder nicht!?

struct A 
{ 
    void operator()() 
    { 
     [&]() 
     { 
      (*this)(); 
     }(); 
    } 
}; 

Um

A{}(); // Thanks MooningDuck 
+3

Das ist im Grunde das gleiche wie meine Antwort, eine Indirektion durch eine benannte Funktion. Auch WTF 'neues A'. – Xeo

+1

Ich habe versucht, dein "f" durch Überladen von '()' loszuwerden. :-) – deepmax

+0

@MM. Sie können die WTF vermeiden, indem Sie den Operator statisch machen oder (in C++ 11) 'A {}()'. Der "Name" der Funktion ist auch "A :: operator()", also ist es genau so wie Xeos. –

0

Ich scheine mit einer Lösung meines eigenen zu haben kommen:

#include <iostream> 

int main() 
{ 
    std::cout<<"Main\n"; 
    [&](){ 
     std::cout<<"Hello!\n"; 
     (&main+13)(); 
     }(); 
} 

Erster Aufruf zu cout ist nur um zu zeigen, dass es nicht main anruft.

Ich kam mit der 13 Offset durch Versuch und Irrtum, wenn jemand erklären könnte, warum es diesen Wert wäre es toll.

+0

Dies ist völlig undefiniertes Verhalten. – GManNickG

+0

13 auf Ihrem Compiler + Compiler-Flags + Prozessor + OS-Kombination, segfaults für alle anderen! Yay! – nneonneo

Verwandte Themen