Wyrażenia lambda, użycie listy parametrów i listy przechwytywania

0

Cześć,

mam następujący fragment kodu.

enum class Colour
{
    Red,
    Blue,
    Black
};

int main()
{
    std::vector<std::pair<Colour, int>> vec;

    vec.push_back(make_pair(Colour::Red, 5));
    vec.push_back(make_pair(Colour::Blue, 10));
    vec.push_back(make_pair(Colour::Black, 15));

    Colour c = Colour::Blue;

    auto foundItem = std::find_if(vec.begin(), vec.end(),
    [&c](const std::pair<Colour, double>& vec)->bool {
        return vec.first == c;
    });

    return 0;
}

W wyrażeniach lambda mamy capture list i parameter list. W przykładzie powyżej specjalnie w liście parametrów jest zdefiniowana para elementów z Color/double pomimo, że powinno być Colour/int. Dlaczego to działa, czy jest to na jakimś etapie w ogóle sprawdzane? Czy to powinno się kompilować? Bo się kompiluje i działa poprawnie.
Zmienna vec, nie została jawnie przekazana do wyrażenia lambda bo nie ma jej na capture list, natomiast jako, że lambda jest wywoływana w find_if to zakładam, że jest to robione niejawnie i tam wewnąrz vec jest przekazywany do wyrażenia jako parametr?

1

To nie ma się nijak do lambd. Po prostu przy przekazywaniu parametru istnieje jedna możliwa konwersja pary, więc do lambdy przekazujesz referencję do zmiennej tymczasowej.

Analogiczny kod:

void foo(pair<int, double> const&)
{
    BARK;
}

int main()
{
    pair a{1,2};
    foo(a);
}

https://wandbox.org/permlink/PAAsmR47p2jXycf1

2
    std::vector<std::pair<Colour, int>> vec;

Do takich rzeczy użyj std::unordered_map<Colour, int> (albo std::map jeśli kolejność w kontenerze jest istotna).

#include <unordered_map>
using namespace std;

enum class Colour
{
	Red,
	Blue,
	Black
};

int main()
{
	unordered_map<Colour, int> vec = {
		{ Colour::Red, 5 },
		{ Colour::Blue, 10 }
	};

	vec[Colour::Black] = 15;

	auto foundItem = vec.find(Colour::Blue);
	int i = foundItem->second;
}
0

Taka uwaga

 [&c](const std::pair<Colour, double>& vec)->bool {
        return vec.first == c;
    });

Tego typu przechwytywanie może być niebezpieczne, nie rzadko warto użyć

 [ c = c] (const std::pair<Colour, double>& vec)->bool {
        return vec.first == c;
    });

Więcej o potencjalnych problemach z lambdami można znaleźć w emc++, w temacie "Materiały dostępne w sieci" jest link.

0

odpowiedź już dostałeś na temat konwersji... dodam tylko, że właśnie ze względu na konwersję typów w późniejszym czasie raczej będziesz wolał stosować "const auto / auto" zamiast dłuższych konstrukcji w stylu "const std::pair<Colour, double>", gdzie możesz się pomylić delikatnie jeśli chodzi o zwracany typ z funkcji który przypisujesz do zmiennej i wykonywać niepotrzebną konwersję typów...

0

IMO gościowi się poplątało, bo zdefiniował sobie parametr lambdy z nazwą, która przykrywa inny symbol. Pewnie maiło być tak:

[c](const std::pair<Colour, double>& x)->bool {
        return x.first == c;
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1