Funkcjonalny (C++)
Standardowa biblioteka C++ |
---|
Kontenery |
Standardowa biblioteka C |
W kontekście języka programowania C++ funkcjonał odnosi
się do pliku nagłówkowego , który jest częścią standardowej biblioteki C++ i zawiera zestaw predefiniowanych szablonów klas dla obiektów funkcyjnych , w tym operacje arytmetyczne, porównania i logikę. Instancje tych szablonów klas to klasy C++ , które definiują operator wywołania funkcji , a instancje tych klas można wywoływać tak, jakby były funkcjami . Możliwe jest wykonywanie bardzo skomplikowanych operacji bez pisania nowego obiektu funkcyjnego, po prostu przez połączenie predefiniowanych obiektów funkcyjnych i adapterów obiektów funkcyjnych.
Szablon klasy std::function
dostarczany przez C++ 11 to opakowanie funkcji polimorficznej ogólnego przeznaczenia . Instancje std::function
mogą przechowywać, kopiować i wywoływać dowolne wywoływalne cele — funkcje, wyrażenia lambda (wyrażenia definiujące funkcje anonimowe ), wyrażenia wiązania (instancje adapterów funkcji, które przekształcają funkcje w inne funkcje o mniejszej liczbie liczb , dostarczając wartości dla niektórych argumenty) lub inne obiekty funkcyjne.
Algorytmy udostępniane przez standardową bibliotekę języka C++ nie wymagają obiektów funkcyjnych o więcej niż dwóch argumentach. Ważnym przypadkiem specjalnym są obiekty funkcyjne, które zwracają wartości logiczne . Funkcja jednoargumentowa , której typem zwracanym jest bool
, nazywana jest predykatem , a funkcja binarna, której typem zwracanym jest bool
, nazywana jest predykatem binarnym .
Adaptowalne obiekty funkcyjne
Ogólnie rzecz biorąc, obiekt funkcji ma ograniczenia co do typu swojego argumentu. Ograniczenia typu nie muszą być jednak proste: operator ()
może być przeciążony lub może być szablonem składowym. Podobnie program nie musi mieć możliwości określenia, jakie są te ograniczenia. Adaptowalny obiekt funkcji określa jednak, jakie są typy argumentów i wartości zwracanych, oraz zapewnia zagnieżdżone definicje typów
, dzięki czemu typy te mogą być nazywane i używane w programach. Jeśli typ F0
jest modelem adaptowalnego generatora, to musi definiować F0 :: typ_wyniku
. Podobnie, jeśli F1
jest modelem adaptowalnej funkcji jednoargumentowej, musi definiować F1 :: typ_argumentu
i F1 :: typ_wyniku
, a jeśli F2
jest modelem adaptowalnej funkcji binarnej, musi definiować F2 :: typ_argumentu
, F2 :: typ_drugiego argumentu
i F2 :: typ_wyniku
. Biblioteka standardowa języka C++ udostępnia klasy podstawowe unary_function
i binary_function
, aby uprościć definiowanie adaptowalnych funkcji jednoargumentowych i adaptowalnych funkcji binarnych.
Adaptowalne obiekty funkcyjne są ważne, ponieważ mogą być używane przez adaptery obiektów funkcyjnych: obiekty funkcyjne, które przekształcają lub manipulują innymi obiektami funkcyjnymi. Biblioteka standardowa C++ udostępnia wiele różnych adapterów obiektów funkcji, w tym unary_negate
(który zwraca logiczne uzupełnienie wartości zwracanej przez określony predykat z możliwością dostosowania) oraz unary_compose
i binary_compose
, które wykonują kompozycję obiektu funkcji.
Predefiniowane obiekty funkcyjne
Biblioteka standardowa C++ zawiera w pliku nagłówkowym funkcjonalnym
wiele różnych predefiniowanych obiektów funkcyjnych, w tym operacje arytmetyczne ( plus
, minus
, mnożenie
, dzielenie
, moduł
i negacja
), porównania ( równa się
, not_równość
, większa
, mniejsza
, większa_równość
i mniejsza_równość
), i operacje logiczne ( logiczne_i
, logiczne_or
i logiczne_nie
).
Przykłady
Opakowania funkcji mogą być używane do wywoływania zwykłych funkcji lub obiektów funkcji utworzonych przez wyrażenia lambda.
#include <iostream> #include <functional> /* Zdefiniuj funkcję szablonu */ template < nazwa typu T > void PrintValue ( wartość T ) { std :: cout << wartość << std :: endl ; } int main ( void ) { /* Opakowanie funkcji dla funkcji */ std :: function < void ( int ) > func_a = PrintValue < int > ; func_a ( 2015 ); /* Opakowanie funkcji na wskaźnik funkcji */ std :: function < void ( int ) > func_b = & PrintValue < int > ; func_b ( 2016 ); /* Opakowanie funkcji dla funkcji lambda. */ std :: function < void ( int ) > func_c = [] ( int value ) { std :: cout << wartość << std :: endl ; }; func_c ( 2017 ); /* Opakowanie funkcji wygenerowane przez std::bind(). * Przekaż predefiniowany parametr podczas wiązania. */ std :: function < void ( void ) > func_d = std :: bind ( PrintValue < std :: string > , "PI to" ); func_d (); /* Opakowanie funkcji wygenerowane przez std::bind(). * Przekaż parametr podczas wywoływania funkcji. */ std :: function < void ( float ) > func_e = std :: bind ( PrintValue < float > , std :: placeholders :: _1 ); func_e ( 3.14159 ); }
Opakowania funkcji mogą być również używane do uzyskiwania dostępu do zmiennych składowych i funkcji składowych klas.
#include <iostream> #include <funkcjonalny> szablon < nazwa typu T > class CAnyData { public : CAnyData ( T value ) : m_value { value } {} void Print ( void ) { std :: cout << m_value << std :: koniec ; } void PrintAfterAdd ( wartość T ) { std :: cout << ( m_value + value ) << std :: endl ; } T m_wartość ; }; int main () { /* Opakowanie funkcji zmiennej składowej klasy */ CAnyData < int > data_a { 2016 }; std :: function < int ( CAnyData < int > & ) > func_a = & CANyData < int >:: m_value ; std :: cout << func_a ( data_a ) << std :: endl ; /* Opakowanie funkcji do funkcji składowej bez przekazywania parametrów */ CAnyData < float > data_b { 2016.1 }; std :: function < void ( CAnyData < float > & ) > func_b = & CAnyData < float >:: Print ; funkcja_b ( dane_b ); /* Opakowanie funkcji do funkcji składowej z przekazaniem parametru */ std :: function < void ( CAnyData < float > & , float ) > func_c = & CAnyData < float >:: PrintAfterAdd ; func_c ( dane_b , 0.1 ); /* Opakowanie funkcji do funkcji składowej wygenerowane przez std::bind */ std :: function < void ( float ) > func_d = std :: bind ( & CAnyData < float >:: PrintAfterAdd , & data_b , std :: placeholders : : _1 ); func_d ( 0.2 ); }