Sdílet prostřednictvím


Syntaxe výrazu lambda

Tento článek ukazuje syntaxe a strukturální elementy lambda výrazy.Popis lambda výrazů naleznete v tématu Výrazy lambda v jazyce C++.

Gramatika výrazů lambda

Následující definice z ISO C ++ 11 standardní ukazuje gramatika z výrazu lambda.(Položky označena opt dolní index jsou volitelné.)

        lambda představení lambda deklarátoroptsloženého prohlášení

Dále jsou uvedeny tyto součásti syntaxe:

Představení lambda:
        [lambda zachyceníopt]
Lambda sběr dat:
        Výchozí sběr dat
        sběr dat seznamu
        zachycení výchozí,zachycení seznamu
sběr dat než výchozí:
        &
        =
sběr dat – seznam:
        zachytit...opt
        zachycení seznamu,zachytit...opt
sběr dat:
        identifikátor
        &identifikátor
        this
Lambda deklarátor:
        (parametr prohlášení klauzule)mutableopt
                Výjimka – specifikaceoptatribut specifikátor sekvenceoptkoncové typ returnvýslovně nesouhlasit

Visual Studio podporuje C ++ 11 standardní lambda výraz syntaxi a funkce, s následujícími výjimkami:

  • Podobně jako všechny ostatní třídy není lambda výrazy získejte konstruktorů automaticky vygenerované přesunout a přesunout operátory přiřazení.Další informace týkající se podpory rvalue odkaz chování, naleznete v části "Odkazy Rvalue" v Podpora funkcí C++11 (moderní jazyk C++).

  • Nepovinný atribut specifikátor sekvence není podporováno v této verzi.

Visual Studio obsahuje tyto funkce kromě C ++ 11 standardní lambda funkce:

  • Bezstavové lambda výrazy, které jsou omni-lze převést na typ ukazatele funkce, které používají libovolný volání konvencí.

  • Automaticky odvozen návratové typy pro lambda subjekty, které jsou složitější než { return expression; }, tak dlouho, dokud všechny vrátíte se příkazy stejného typu.(Tato funkce je součástí navržené C ++ 14 standardu.)

Vlastnosti výrazů lambda

Tento obrázek mapuje gramatika příklad:

Strukturální prvky výrazu lambda

  1. lambda představení (také označované jako zachycení klauzule)

  2. lambda deklarátor (také označované jako seznam parametrů)

  3. měnitelný (také označované jako měnitelný specifikace)

  4. Výjimka – specifikace (také označované jako výjimky specifikace)

  5. koncové typ return (také označované jako Návratový typ)

  6. složeného prohlášení (také označované jako lambda textu)

Klauzule zachycení

Výraz lambda je v podstatě třída, konstruktor a operátor volání funkce.Stejně jako při definování třídy v lambda musíte rozhodnout, zda výsledný objekt zaznamená proměnné podle hodnoty, odkaz nebo vůbec.Pokud výrazu lambda má přístup k místní proměnné a parametry funkce, musí být zachyceny.Klauzuli sběr dat (lambda představení v standardní syntaxe) určuje, zda datové části výrazu lambda získat přístup k proměnné v oboru nadřazených hodnotu nebo odkazem.Proměnné, které mají ampersand (&) předpona přistupují odkaz a proměnné, které nemají přistupují hodnotu.

Klauzuli prázdné zachycení [ ], označuje, že tělo výrazu lambda přistupuje žádné proměnné v nadřazených oboru.

Můžete použít výchozí režim sběr dat (capture-default v standardní syntaxe) tak, aby zachytával Nespecifikovaná proměnné hodnotu nebo odkazem.Zadejte výchozí režim sběr dat pomocí & nebo = jako první element klauzule zachycení.& Element říká datové části výrazu lambda pro přístup k nespecifikované proměnné odkazem.= Element říká lambda textu pro přístup k nespecifikované proměnné podle hodnoty.Například pokud lambda textu přistupuje externí proměnné total odkazem a externí proměnné factor podle hodnoty, pak následující klauzule sběr dat jsou ekvivalentní:

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

Běžné nesprávné pojetí o capture-default je, že jsou zachyceny všechny proměnné v oboru, zda se používají v argument lambda, či nikoli.Toto není případ – pouze proměnné, které jsou uvedeny v argument lambda jsou zachyceny při capture-default se používá.

Pokud zachycení klauzule obsahuje capture-default&, pak žádné identifier v capture tohoto zachycení klauzule může mít formulář & identifier.Podobně platí Pokud klauzule zachycení obsahuje capture-default=, pak žádné capture tohoto zachycení klauzule může mít formulář = identifier.Identifikátor nebo this nemůže být více než jednou použit v klauzuli zachycení.Následující fragment kódu dokládá několik příkladů.

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
}

Objekt capture za nímž následuje třemi tečkami je sada růst, jak je znázorněno v tomto variadic šablona příklad:

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

Můžete použít výrazy lambda v těle metody třídy.Předat this ukazatel na klauzuli sběr dat k poskytování přístupu k metody a data členů ohraničující třídy.Příklad ukazuje, jak lze pomocí metody třídy lambda výrazy, naleznete v části "Příklad: Lambda výraz v metodou" v Příklady výrazů lambda.

Pokud použijete klauzuli sběr dat, doporučujeme, abyste zachování těchto bodů na paměti, zejména pokud použijete lambda výrazy s multithreadingu:

  • Zachycení odkazu lze použít pro úpravy proměnných mimo, ale nelze zachycení hodnotu.(mutable umožňuje kopií, které chcete upravit, ale není původní.)

  • Odkaz na zachycení odrážejí aktualizace na proměnné mimo, ale zachycení hodnotu nepodporují.

  • Referenční zachycení zavést závislost na životnost, ale zachycení hodnotu nemají žádné závislosti životnosti.

Seznam parametrů

Seznam parametrů (lambda deklarátor v standardní syntaxe) je volitelná a vypadat například takto: seznam parametrů pro funkci.

Výraz lambda může jako svůj argument přijmout jiný výraz lambda.Další informace naleznete v tématu "Vyšší pořadí Lambda výrazy" v tématu Příklady výrazů lambda.

Vzhledem k tomu, že je volitelný seznam parametrů, můžete vynechat závorky, pokud není předáním argumentů výrazu lambda a jeho lambda-declarator: neobsahuje Výjimka – specifikace, koncové typ return, nebo mutable.

Proměnlivé specifikace

Operátor volání funkcí lambda je obvykle b podle hodnot, ale využívání mutable klíčové slovo zruší tento.Nevytváří proměnlivé datové členy.Proměnlivé specifikace umožňují hlavní části výrazu lambda upravit proměnné, které jsou zachyceny hodnotou.Některé příklady dále v tomto článku ukazují, jak používat mutable.

Specifikace výjimek

Můžete použít throw() výjimky specifikace označuje, že výrazu lambda nevyvolá všechny výjimky.Jako pomocí běžných funkcí kompilátor Visual C++ generuje varování C4297 Pokud výrazu lambda deklaruje throw() specifikace výjimky a textu lambda vyvolá výjimku, jak je znázorněno zde:

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

Další informace naleznete v tématu Specifikace výjimek.

Návratový typ

Návratový typ výrazu lambda je automaticky odvozen.Nemáte express automaticky klíčové slovo neurčíte koncové typ return.Koncové typ return vypadat například takto: typ return část běžných metody nebo funkce.Však návratový typ musí následovat seznam parametrů, a musí obsahovat klíčové slovo koncové typ return -> před návratový typ.

Typ return část výrazu lambda lze vynechat, pokud lambda text obsahuje pouze jeden příkaz return nebo výraz nevrací hodnotu.Pokud lambda text obsahuje jeden příkaz return, kompilátor deduces návratový typ z typu vrácené výrazem.V opačném kompilátor deduces návratový typ, který má být void.Zvažte následující příklad fragmentu kódu, který ilustruje tento princip.

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

Výraz lambda může jako vrácenou hodnotu vytvořit jiný výraz lambda.Další informace naleznete v části "Vyšší pořadí Lambda výrazy" v Příklady výrazů lambda.

Hlavní část výrazu lambda

Datové části lambda (složeného prohlášení v standardní syntaxe) z lambda výraz může obsahovat cokoli, co může obsahovat text běžných metody nebo funkce.Text běžných funkce a výrazu lambda přístup těchto druhů proměnné:

  • Parametry

  • Místně deklarované proměnné

  • Třídy datových členů, pokud deklarován uvnitř třídy a this zaznamenat

  • Každá proměnná, která má dobu trvání statické úložiště – například globální proměnné

Kromě toho výraz lambda má přístup k proměnným, které zachytí z nadřazeného rámce.Proměnná je explicitně zachycené Pokud se zobrazí v klauzuli zachycení výrazu lambda.V opačném proměnná je implicitně zachycené.Hlavní část výrazu lambda používá pro přístup k implicitně zachyceným proměnným výchozí režim sběru dat.

Následující příklad obsahuje výraz lambda, která explicitně zaznamená proměnné n podle hodnoty a implicitně zaznamená proměnné m odkazem:

// 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;
}

Výstup:

  

Protože proměnné n zaznamenat podle hodnoty, zůstane její hodnota 0 Po volání výrazu lambda.mutable Povoluje specifikace n má být upraven v rámci argument lambda.

Přestože výraz lambda může zachytit pouze proměnné, které mají automatickou dobu ukládání, můžete použít proměnné, které mají statickou dobu ukládání v hlavní části výrazu lambda.V následujícím příkladu generate funkce a přiřadit hodnotu pro každý prvek ve výrazu lambda vector objektu.Výraz lambda změní statickou proměnnou a vygeneruje tak hodnotu dalšího prvku.

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
}

Další informace naleznete v tématu generate.

Následující příklad kódu používá funkci z předchozího příkladu a přidá příklad výrazu lambda, která používá algoritmus STL generate_n.Tento výraz lambda přiřadí element vector objekt, který má součet předchozí dva elementy.mutable Klíčové slovo je použito tak, aby datové části výrazu lambda můžete upravovat jeho kopie externí proměnné x a y, která výrazu lambda zachycuje podle hodnoty.Vzhledem k tomu, že výrazu lambda zaznamená původní proměnné x a y podle hodnoty, jejich hodnoty zůstávají 1 Po provedení argument 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);
}

Výstup:

  

Další informace naleznete v tématu generate_n.

Modifikátory specifické pro společnost Microsoft

Pokud například používáte modifikátor specifické pro společnost Microsoft __declspec, můžete jej přidat do výrazu lambda ihned po parameter-declaration-clause– například:

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

Chcete-li zjistit, zda je modifikátor podporován lambda výrazy, naleznete v článku o jej v Modifikátory specifické pro společnost Microsoft části dokumentace.

Viz také

Referenční dokumentace

Výrazy lambda v jazyce C++

Příklady výrazů lambda

generate

generate_n

for_each

Specifikace výjimek

Upozornění kompilátoru (úroveň 1) C4297

Modifikátory specifické pro společnost Microsoft