Funktionsliterale in C++
Funktionsnamen
main.cpp
#include <iostream>
#include <ostream>
int f(){ return 2; }
int main()
{ ::std::cout <<f
() << '\n'; }
::std::cout
2
Funktionsliterale
Eine Funktion kann direkt am Ort ihrer Verwendung angegeben werden. Dazu ist sie mit einem vorangestellten »[]« zu kennzeichnen.
main.cpp
#include <iostream>
#include <ostream>
int main()
{ ::std::cout <<[]{ return 2; }
() << '\n'; }
::std::cout
2
Die Funktion ist »[]{ return 2; }«. Danach folgt »()« zum Aufruf.
Falls der Typ der Funktion in einer Variablendefinition nicht verwendet werden soll, kann »auto« als Platzhalter verwendet werden.
main.cpp
#include <iostream>
#include <ostream>
int main()
{ auto f = []{ return 2; };
::std::cout << f() << '\n'; }
::std::cout
2
Ein anderes Beispiel:
main.cpp
int main(){ []{}(); }
::std::cout
- (keine Ausgabe.)
Ein Funktionsliteral wird auch Lambda-Ausdruck oder kurz Lambda genannt.
Ausführlichere Funktionsliterale
Bei der oben gezeigten Kurzform von Funktionsliteralen wurde die Parameterliste weggelassen. Statt dessen kann auch eine Parameterliste geschrieben werden.
Kurzform ohne Parameterliste
main.cpp
int main(){ []{}(); }
::std::cout
- (keine Ausgabe.)
Form mit Parameterliste
main.cpp
int main(){ [](){}(); }
::std::cout
- (keine Ausgabe.)
Das Weglassen der Parameterliste ist nicht mehr möglich, wenn bestimmte weitere Bestandteile zum Funktionsliteral hinzugefügt werden.
Ein Rückgabetyp kann mit »->« angegeben. Dann müssen auch die runden Klammern für eine leere Parameterliste geschrieben werden.
main.cpp
#include <iostream>
#include <ostream>
int main()
{ ::std::cout << []()->int{ return 65; }() << '\n';
::std::cout << []()->char{ return 65; }() << '\n'; }
::std::cout
65
A
In den runden Klammern können Parameter deklariert werden.
main.cpp
#include <iostream>
#include <ostream>
int main()
{ ::std::cout << []( int const x ){ return 2 * x; }( 12 ) << '\n'; }
::std::cout
Mit Funktionsliteralen ist es bequemer, Funktionen an Algorithmen zu übergeben.
main.cpp
#include <iostream>
#include <ostream>
#include <string>
#include <algorithm>
bool is_vowel( char const ch ) /* "callback function" */
{ return ::std::string{ "aeiou" }.find( ch )!= ::std::string::npos; }
int main()
{ ::std::string str{ "abcdefghijklmnopqrstuvwxyz" };
remove_if( begin( str ), end( str ), is_vowel );
::std::cout << str << '\n'; }
main.cpp
#include <iostream>
#include <ostream>
#include <string>
#include <algorithm>
#include <initializer_list>
int main()
{ ::std::string str{ "abcdefghijklmnopqrstuvwxyz" };
remove_if
( begin( str ), end( str ), []( char const ch )->bool
{ return ::std::string{ "aeiou" }.find( ch )!= ::std::string::npos; });
::std::cout << str << '\n'; }
Die Schreibweise mit »->« kann auch bei benannten Funktionen verwendet werden. Der Platzhalter »auto« steht dabei an der Stelle, an welcher sonst der Rückgabetyp stehen würde.
main.cpp
#include <iostream>
#include <ostream>
auto f() -> int{ return 2; }
int main(){ ::std::cout << f() << '\n'; }
::std::cout
2
#include <iostream>
#include <ostream>
Bindungen
Ohne Bindung kann »a« nicht erreicht werden.
#include <iostream>
#include <ostream>
int main()
{ ::std::string a{ "alpha" };
[](){ ::std::cout << a << "\n"; }(); }
Im folgenden Programm steht »a« in der namenlosen Funktion für eine Kopie von »a« in main.
#include <iostream>
#include <ostream>
#include <iostream>
#include <ostream>
int main()
{ ::std::string a{ "alpha" };
[ = ](){ ::std::cout << a << "\n"; }(); }
Jedes Funktionsliteral hat seinen eigenen Typ, aber dieser ist verträglich mit einem ::std::function-Typ, der sich aus den Typen der Parameter und des Ergebnisses zusammensetzt.
main.cpp
#include <iostream>
#include <ostream>
#include <functional>
::std::function< int( int )>make_adder( int const x )
{ return [=]( int const y ){ return x + y; }; }int main()
{ auto adder5 = make_adder( 5 );
::std::cout << adder5( 2 )<< '\n';
::std::cout << adder5( 4 )<< '\n'; }::std::cout
7
9
Bindungen in Funktionsliteralen
Im folgenden Programm steht »a« in der namenlosen Funktion für eine Referenz auf »a« in main.
#include <iostream>
#include <ostream>
int main()
{ ::std::string a{ "alpha" };
[ & ](){ ::std::cout << a << "\n"; }(); }
main.c
#include <iostream>
#include <ostream>void main0()
{ ::std::cout << "main0" << '\n';
auto x{ 1 };
{ x = 2; ::std::cout << "x = " << x << '\n'; }
::std::cout << "x = " << x << '\n'; }void main1()
{ ::std::cout << "main1" << '\n';
auto x{ 1 };
[ = ]() mutable { x = 2; ::std::cout << "x = " << x << '\n'; }();
::std::cout << "x = " << x << '\n'; }int main()
{ main0(); ::std::cout << '\n';
main1(); }::std::cout
main0
x = 2
x = 2main1
x = 2
x = 1
Beispiel Sortieren einer char-*-Reihung
Ein Reihung von C-Folgen kann verhältnismäßig einfach sortiert werden, da die C-Folgen in vielen Fällen implizit in C++-Folgen gewandelt werden. Dabei wird davon Gebrauch gemacht, daß ein Temporär an eine konstanten Referenz gebunden werden kann.
#include <iostream>
#include <ostream>
#include <algorithm>
#include <iterator>
#include <string>
#include <initializer_list>
int main()
{ char const * a[] =
{ "omicron", "pi", "phi", "chi", "epsilon", "rho", "sigma", "tau", "upsilon",
"nu", "xi", "zeta", "gamma", "eta", "theta", "psi", "omega", "alpha",
"beta", "delta", "iota", "kappa", "lambda", "mu", };
::std::sort( ::std::begin( a ), ::std::end( a ),
[]( std::string const & l, std::string const & r )-> bool{ return !( r < l ); } );
::std::copy( ::std::begin( a ), ::std::end( a ),
::std::ostream_iterator< ::std::string >( ::std::cout, "\n" )); }