Składnia wyrażenia lambda

W tym artykule przedstawiono składnię i elementy strukturalne wyrażenia lambda.Opis wyrażenia lambda, zobacz Wyrażenia lambda w języku C++.

Gramatyka wyrażenia lambda

Gramatyki przedstawiono definicję z C ++ 11 normy ISO wyrażenia lambda.(Elementy oznaczona za pomocą wyrażać dolny są opcjonalne.)

        lambda introducer lambda-declaratorwyrażaćinstrukcji związek

Dodatkowo określono tych składników składni:

lambda introducer:
        [lambda przechwytywaniawyrażać]
Przechwytywanie lambda:
        Przechwytywanie domyślne
        Lista przechwytywania
        domyślne przechwytywania,listy przechwytywania
Wartość domyślna przechwytywania:
        &
        =
Lista przechwytywania:
        Przechwytywanie...opt
        listy przechwytywania,Przechwytywanie...opt
Przechwytywanie:
        identyfikator
        &identyfikatora
        this
lambda declarator:
        (parametr deklaracji klauzuli)mutablewyrażać
                specyfikacji wyjątekwyrażaćatrybut specyfikator Sekwencjonowanyzrezygnowaćkońcowe zwraca typ-wyrażać

Program Visual Studio obsługuje C ++ 11 standardowe lambda składnia wyrażeń i funkcji, z następującymi wyjątkami:

  • Podobnie jak inne klasy lambdas nie zapoznaj się automatycznie generowanej przenoszenia konstruktorów i Przenieś operatory przypisania.Aby uzyskać więcej informacji na temat pomocy technicznej dla zachowania odwołania rvalue zawiera sekcja w dokumencie "Odwołania Rvalue" Obsługa dla funkcji C++11 (Modern C++).

  • Opcjonalna atrybut specyfikator Sekwencjonowany nie jest obsługiwana w tej wersji.

Program Visual Studio zawiera następujące funkcje, oprócz funkcji 11 standardowe lambda C ++:

  • Bezstanowa lambdas będące omni — można przekonwertować na typ wskaźników funkcji, korzystających z dowolnego elementu wywołującego Konwencji.

  • Automatycznie ustalane zwracanych typów dla treści lambda, które są bardziej skomplikowane od { return expression; }, tak długo, jak zwracają instrukcji ma tego samego typu.(Ta funkcja jest proponowana C ++ 14 standardowej).

Właściwości wyrażeń lambda

Ilustracji mapuje gramatyki, na przykład:

Elementy strukturalne wyrażenia lambda

  1. lambda introducer (znanego także jako klauzuli przechwytywania)

  2. lambda declarator (znanego także jako Lista parametrów)

  3. modyfikowalną (znanego także jako specyfikacji modyfikowalną)

  4. specyfikacji wyjątek (znanego także jako specyfikacji wyjątek)

  5. końcowe zwraca typ- (znanego także jako zwracany typ)

  6. instrukcji związek (znanego także jako treści lambda)

Klauzula przechwytywania

Wyrażenie lambda jest zasadniczo klasą, konstruktorem oraz operatorem wywołania funkcji.Tak, jak podczas definiowania klasę, w lambda należy określić, czy obiekt wynikowy przechwytuje zmienne według wartości, mocy odwołania lub wcale.Wyrażenie lambda ma dostęp do zmiennych lokalnych i parametry funkcji, muszą być przechwycone.Klauzula przechwytywania (lambda introducer w standardowej składni) określa czy treść wyrażenia lambda mogą uzyskać dostęp zmiennych w zakresie otaczającego przez wartość lub przez odwołanie.Zmienne, które mają handlowe "i" (&) prefiks są dostępne dla odwołania i zmiennych, które nie mają wartości są dostępne.

Klauzula przechwytywania puste, [ ], wskazuje, że treść wyrażenia lambda uzyskuje dostęp do Brak zmiennych w zakresie otaczającego.

Służy to domyślny tryb przechwytywania (capture-default w standardowej składni) do przechwytywania nieokreślony zmienne przez wartość lub przez odwołanie.Określ domyślny tryb przechwytywania za pomocą & lub = jako pierwszy element klauzuli przechwytywania.& Elementu informuje wyrażenia lambda dostęp nieokreślony zmiennych w odniesieniu do treści.= Elementu informuje treści lambda uzyskać dostęp do zmiennych nieokreślony przez wartość.Na przykład, jeśli treść lambda uzyskuje dostęp do zewnętrznych zmiennej total odwołania i zewnętrznego zmiennej factor według wartości, następnie następujące klauzule przechwytywania są równoważne:

[&total, factor]
[factor, &total]
[&, factor]
[factor, &]
[=, &total]
[&total, =]

Wspólne przekonanie o capture-default jest, że wszystkie zmienne w zakresie są przechwytywane, czy też nie są używane w lambda.Nie jest uruchomiona — tylko w przypadku zmiennych, które są wymienione w lambda są przechwytywane podczas capture-default jest używany.

Jeśli zawiera klauzulę przechwytywania capture-default&, nie identifier w capture z tym przechwytywania klauzuli może mieć postać & identifier.Podobnie jeśli zawiera klauzuli przechwytywania capture-default=, nie capture tego przechwytywania klauzuli może mieć postać = identifier.Identyfikator lub this nie może występować więcej niż raz w klauzuli przechwytywania.Poniższy fragment kodu ilustruje kilka przykładów.

struct S { void f(int i); };

void S::f(int i) {
    [&, i]{};    // OK
    [&, &i]{};   // ERROR: i preceded by & when & is the default
    [=, this]{}; // ERROR: this when = is the default
    [i, i]{};    // ERROR: i repeated
}

Element capture następuje wielokropka jest rozszerzeniem pakiet, jak pokazano w tym szablonu variadic przykład:

template<class... Args>
void f(Args... args) {
    auto x = [args...] { return g(args...); };
    x();
}

Można używać wyrażeń lambda w treści metody klasy.Przekaż this wskaźnik do klauzuli przechwytywania umożliwia dostęp do metod i danych elementów członkowskich otaczającego klasy.Przykład przedstawia użycie wyrażenia lambda za pomocą metod klasy, zobacz "Przykład: przy użyciu Lambda wyrażenie w metodzie" w Przykłady wyrażeń lambda.

Gdy użytkownik korzysta z klauzuli przechwytywania, zalecamy należy punkty pamiętać, zwłaszcza w przypadku, gdy użytkownik korzysta z lambdas z wielowątkowości:

  • Służy do modyfikowania zmiennych poza przechwytywane odwołania, ale nie przechwytywane wartość.(mutable umożliwia kopii można zmodyfikować, ale nie oryginałów.)

  • Aktualizacje do zmiennych poza odzwierciedlają przechwytywane odwołania, ale przechwytywane wartość nie.

  • Odwołania przechwytywane wprowadzenie zależność okres istnienia, ale nie zależności okres istnienia ma wartość przechwytywane.

Lista parametrów

Lista parametrów (lambda declarator w standardowej składni) jest opcjonalna i podobny na liście parametrów dla funkcji.

Wyrażenie lambda może przyjmować inne wyrażenie lambda jako argument.Aby uzyskać więcej informacji, zobacz "Wyrażenia Lambda wyższego kolejność" w temacie Przykłady wyrażeń lambda.

Lista parametrów jest opcjonalna, można pominąć pustych nawiasów, jeśli argument nie jest przekazywany do wyrażenia lambda i jego lambda-declarator: nie zawiera specyfikacji wyjątek, końcowe zwraca typ-, lub mutable.

Specyfikacja modyfikowalna

Operator wywołania funkcji lambda jest zwykle stała według wartości, ale korzystanie z mutable anuluje słowo kluczowe to.Nie generuje to modyfikowalnych elementów członkowskich danych.Specyfikacja modyfikowalna umożliwia treści wyrażenia lambda modyfikację zmiennych, które są przechwytywane przez wartość.Przykłady w tym artykule przedstawiono sposoby używania mutable.

Specyfikacja wyjątku

Można użyć throw() specyfikacji wyjątek, jeśli wyrażenie lambda wyjątku wyjątki.Zgodnie z normalnych funkcji Kompilator Visual C++ generuje ostrzeżenie C4297 Jeśli deklaruje wyrażenia lambda throw() specyfikacji wyjątku i treść lambda zgłasza wyjątek, jak pokazano poniżej:

// throw_lambda_expression.cpp
// compile with: /W4 /EHsc 
int main() // C4297 expected
{
   []() throw() { throw 5; }();
}

Aby uzyskać więcej informacji, zobacz Specyfikacje wyjątków.

Typ zwracany

Wyrażenie lambda typ zwrotny jest automatycznie ustalane.Nie masz express automatycznie słowo kluczowe chyba że zostanie końcowe zwraca typ-.Końcowe zwraca typ- podobny typ zwrotu część zwykłych metody lub funkcji.Jednak typ zwrotny należy wykonać na liście parametrów i musi zawierać słowa kluczowego końcowe zwraca typ- -> przed typ zwrotny.

Można pominąć część zwraca typ wyrażenia lambda, jeśli treść lambda zawiera tylko jedną instrukcję zwrotny lub wyrażenie nie zwraca wartości.Jeśli treść lambda zawiera jednej instrukcji return, kompilator deduces typ zwrotny z wyrażenia zwracanego typu.W przeciwnym razie kompilator deduces typ zwrotny jako void.Rozważmy następujące przykładowe fragmenty kodu, które ilustrują tę zasadę.

auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return{ 1, 2 }; };  // ERROR: return type is void, deducing 
                                  // return type from braced-init-list is not valid

Wyrażenie lambda może generować inne wyrażenie lambda jako wartość zwracaną.Aby uzyskać więcej informacji, zobacz "Wyrażenia Lambda wyższego kolejność" w Przykłady wyrażeń lambda.

Treść lambda

Treść lambda (instrukcji związek w standardowej składni) z lambda wyrażenie może zawierać wszystkie elementy zawierające treść metody normalnych lub funkcji.Treść zwykłej funkcji i wyrażenia lambda uzyskać dostęp do tych rodzajów zmiennych:

  • Parametry

  • Lokalnie deklarowane zmienne

  • Klasy elementów członkowskich danych, gdy zadeklarowanych w klasie i this jest przechwytywana

  • Wszelkie zmiennej, która ma czas trwania statycznych magazynu — na przykład zmienne globalne

Dodatkowo wyrażenie lambda może uzyskać dostęp do zmiennych, które przechwytuje z otaczającego zasięgu.Zmienna jest jawnie przechwycone występuje w klauzuli przechwytywania wyrażenia lambda.W przeciwnym razie jest zmienna niejawnie przechwycone.Treść wyrażenia lambda wykorzystuje domyślny tryb przechwytywania, aby uzyskać dostęp do zmiennych, które są przechwytywane niejawnie.

Poniższy przykład zawiera wyrażenia lambda, który jawnie przechwytuje zmiennej n przez wartość i niejawnie przechwytuje zmiennej m mocy odwołania:

// captures_lambda_expression.cpp
// compile with: /W4 /EHsc 
#include <iostream>
using namespace std;

int main()
{
   int m = 0;
   int n = 0;
   [&, n] (int a) mutable { m = ++n + a; }(4);
   cout << m << endl << n << endl;
}

Dane wyjściowe:

  

Ponieważ zmienna n jest przechwytywana przez wartość, jego wartość pozostaje 0 po wywołaniu wyrażenia lambda.mutable Specyfikacja umożliwia n można zmodyfikować w ramach lambda.

Mimo że wyrażenie lambda może przechwytywać tylko zmienne, które mają automatyczny czas trwania przechowywania, można używać zmiennych o statycznym czasie trwania przechowywania w treści wyrażenia lambda.W poniższym przykładzie użyto generate funkcji i wyrażenia lambda, aby przypisać wartości do poszczególnych elementów w vector obiektu.Wyrażenie lambda modyfikuje zmienną statyczną, aby wygenerować wartość następnego elementu.

void fillVector(vector<int>& v)
{
    // A local static variable.
    static int nextValue = 1;

    // The lambda expression that appears in the following call to
    // the generate function modifies and uses the local static 
    // variable nextValue.
    generate(v.begin(), v.end(), [] { return nextValue++; }); 
    //WARNING: this is not thread-safe and is shown for illustration only
}

Aby uzyskać więcej informacji, zobacz generate.

Poniższy przykładowy kod jest używana funkcja z poprzedniego przykładu i dodaje przykład wyrażenia lambda, który używa algorytmu STL generate_n.Wyrażenie lambda przypisuje element vector obiektu sumie poprzednie dwa elementy.mutable Użycie słowa kluczowego, aby treść wyrażenia lambda można zmodyfikować jego kopię zmiennych zewnętrznych x i y, który przechwytuje wyrażenia lambda przez wartość.Ponieważ wyrażenie lambda przechwytuje oryginalnego zmienne x i y według wartości, pozostają ich wartości 1 po lambda.

// compile with: /W4 /EHsc
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>

using namespace std;

template <typename C> void print(const string& s, const C& c) {
    cout << s;

    for (const auto& e : c) {
        cout << e << " ";
    }

    cout << endl;
}

void fillVector(vector<int>& v)
{
    // A local static variable.
    static int nextValue = 1;

    // The lambda expression that appears in the following call to
    // the generate function modifies and uses the local static 
    // variable nextValue.
    generate(v.begin(), v.end(), [] { return nextValue++; });
    //WARNING: this is not thread-safe and is shown for illustration only
}

int main()
{
    // The number of elements in the vector.
    const int elementCount = 9;

    // Create a vector object with each element set to 1.
    vector<int> v(elementCount, 1);

    // These variables hold the previous two elements of the vector.
    int x = 1;
    int y = 1;

    // Sets each element in the vector to the sum of the 
    // previous two elements.
    generate_n(v.begin() + 2,
        elementCount - 2,
        [=]() mutable throw() -> int { // lambda is the 3rd parameter
        // Generate current value.
        int n = x + y;
        // Update previous two values.
        x = y;
        y = n;
        return n;
    });
    print("vector v after call to generate_n() with lambda: ", v);

    // Print the local variables x and y.
    // The values of x and y hold their initial values because 
    // they are captured by value.
    cout << "x: " << x << " y: " << y << endl;

    // Fill the vector with a sequence of numbers
    fillVector(v);
    print("vector v after 1st call to fillVector(): ", v);
    // Fill the vector with the next sequence of numbers
    fillVector(v);
    print("vector v after 2nd call to fillVector(): ", v);
}

Dane wyjściowe:

  

Aby uzyskać więcej informacji, zobacz generate_n.

Modyfikatory specyficzne dla firmy Microsoft

Jeśli używasz modyfikator specyficzne dla firmy Microsoft takich jak __declspec, można wstawić go do wyrażenia lambda bezpośrednio po parameter-declaration-clause— na przykład:

auto Sqr = [](int t) __declspec(code_seg("PagedMem")) -> int { return t*t; };

Aby ustalić, czy modyfikator jest obsługiwana przez lambdas, zobacz artykuł o nim w modyfikatorów specyficzne dla programu Microsoft sekcji dokumentacji.

Zobacz też

Informacje

Wyrażenia lambda w języku C++

Przykłady wyrażeń lambda

generate

generate_n

for_each

Specyfikacje wyjątków

Ostrzeżenie kompilatora (poziom 1) C4297

Modyfikatory specyficzne dla firmy Microsoft