Użycie i składnia std:: function

Jest mi konieczne użycie std::function, ale nie wiem, co oznacza następująca składnia.

std::function<void()> f_name = []() { FNAME(); };

Jaki jest cel używania std::function? Czy jest to wskaźnik do funkcji?

Author: Yakk - Adam Nevraumont, 2013-12-03

2 answers

std::function jest obiektem typu erasure. Oznacza to, że usuwa szczegóły dotyczące przebiegu niektórych operacji i zapewnia im jednolity interfejs czasu wykonywania. Dla std::function, podstawowy1 operacje to kopiowanie/przenoszenie, niszczenie i 'wywoływanie' z operator() -- 'funkcja jak operator wywołania'.

W mniej zawiłym angielskim oznacza to, że std::function może zawierać prawie każdy obiekt, który działa jak wskaźnik funkcji w sposób, w jaki go nazywasz.

Podpis, który obsługuje, znajduje się wewnątrz nawiasy kątowe: std::function<void()> pobiera zero argumentów i nie zwraca nic. std::function< double( int, int ) > pobiera dwa argumenty int i zwraca double. Ogólnie rzecz biorąc, std::function obsługuje przechowywanie dowolnego obiektu podobnego do funkcji, którego argumenty mogą być konwertowane-z listy argumentów i którego wartość zwracana może być konwertowana-na jego wartość zwracaną.

Ważne jest, aby wiedzieć, że std::function i lambdy są różnymi, jeśli są kompatybilne, bestiami.

Następna część wiersza to lambda. Jest to nowa składnia w C++11, aby dodać możliwość napisz proste obiekty podobne do funkcji -- obiekty, które mogą być wywoływane przez (). Takie obiekty mogą być kasowane i przechowywane w std::function kosztem pewnego czasu pracy.

[](){ code } w szczególności jest to bardzo prosta lambda. Odpowiada temu:

struct some_anonymous_type {
  some_anonymous_type() {}
  void operator()const{
    code
  }
};

Instancja powyższego prostego typu pseudo-funkcji. Rzeczywista Klasa jak wyżej jest "wymyślona" przez kompilator, o unikalnej nazwie zdefiniowanej przez implementację (często zawierającej symbole, których żaden typ nie może contain) (Nie wiem, czy jest możliwe, że można postępować zgodnie ze standardem bez wymyślania takiej klasy, ale każdy kompilator, którego znam, tworzy klasę).

Pełna składnia lambda wygląda następująco:

[ capture_list ]( argument_list )
-> return_type optional_mutable
{
  code
}

Ale wiele części można pominąć lub pozostawić puste. Capture_list odpowiada zarówno konstruktorowi wynikowego anonimowego typu, jak i jego zmiennym składowym, argument_list argumentom operator(), A Typ return Typ return. Konstruktor instancja lambda jest również magicznie wywoływana, gdy instancja jest tworzona za pomocą capture_list.

[ capture_list ]( argument_list ) -> return_type { code }

W zasadzie staje się

struct some_anonymous_type {
  // capture_list turned into member variables
  some_anonymous_type( /* capture_list turned into arguments */ ):
    /* member variables initialized */
  {}
  return_type operator()( argument_list ) const {
    code
  }
};

Zauważ, że w c++20 argumenty szablonu zostały dodane do lambda, a to nie jest opisane powyżej.

[]<typename T>( std::vector<T> const& v ) { return v.size(); }

1 ponadto zapisywany jest RTTI (typeid) i dołączona jest operacja cast-back-to-original-type.

 110
Author: Yakk - Adam Nevraumont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-04 12:53:56

Rozłammy linię:

Std:: function

Jest to deklaracja dla funkcji nie pobierającej parametrów i nie zwracającej żadnej wartości. Jeśli funkcja zwraca int, wyglądałaby tak:

std::function<int()>

Podobnie, jeśli wziął również parametr int:

std::function<int(int)>

Podejrzewam, że głównym zamieszaniem jest następna część.

[]() { FNAME(); };

Część [] nazywa się klauzulą przechwytywania. Tutaj umieszczasz zmienne, które są lokalne do deklaracji twojego lambda, i że chcesz być dostępny wewnątrz samej funkcji lambda. To jest powiedzenie "nie chcę, żeby coś zostało schwytane". Jeśli to mieści się w definicji klasy i chcesz, aby klasa była dostępna dla lambda, możesz to zrobić: {]}

[this]() { FNAME(); };

Następna część to parametry przekazywane do lambda, dokładnie tak samo, jak gdyby była to zwykła funkcja. Jak wspomniano wcześniej, std::function<void()> jest sygnałem wskazującym na metodę, która nie przyjmuje parametrów, więc jest to pusto też.

Reszta jest ciałem samej lambdy, jakby była to funkcja regularna, którą widzimy tylko wywołując funkcję FNAME.

Inny Przykład

Załóżmy, że masz następujący podpis, czyli coś, co może zsumować dwie liczby.

std::function<int(int, int)> sumFunc;

Możemy teraz ogłosić lambdę w ten sposób:

sumFunc = [](int a, int b) { return a + b; };

Nie wiem, czy używasz MSVC, ale tutaj jest link do wyrażenia lamda składnia:

Http://msdn.microsoft.com/en-us/library/dd293603.aspx

 42
Author: Moo-Juice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 14:14:47