Chcę utworzyć std::set
z niestandardową funkcją porównania. Mógłbym zdefiniować go jako klasę z operator()
, ale chciałem cieszyć się możliwością zdefiniowania lambda, gdzie jest on używany, więc zdecydowałem się zdefiniować funkcję lambda na liście inicjalizacyjnej konstruktora klasy, który ma std::set
jako członek. Ale nie mogę uzyskać typu lambda. Zanim przystąpię, oto przykład:C++ 11 std :: ustaw funkcję porównania lambda
class Foo
{
private:
std::set<int, /*???*/> numbers;
public:
Foo() : numbers ([](int x, int y)
{
return x < y;
})
{
}
};
znalazłem dwa rozwiązania po poszukiwaniach: jeden, używając std::function
. Po prostu ustaw typ funkcji porównania na std::function<bool (int, int)>
i przeprowadź lambdę dokładnie tak jak ja. Drugim rozwiązaniem jest napisanie funkcji make_set, takiej jak std::make_pair
.
ROZWIĄZANIE 1:
class Foo
{
private:
std::set<int, std::function<bool (int, int)> numbers;
public:
Foo() : numbers ([](int x, int y)
{
return x < y;
})
{
}
};
Rozwiązanie 2:
template <class Key, class Compare>
std::set<Key, Compare> make_set (Compare compare)
{
return std::set<Key, Compare> (compare);
}
Pytanie brzmi, czy mam dobry powód, aby preferować jednego rozwiązania nad drugim? Wolę pierwszy, ponieważ korzysta on ze standardowych funkcji (make_set nie jest standardową funkcją), ale zastanawiam się: czy użycie kodu std::function
powoduje, że kod (potencjalnie) jest wolniejszy? Chodzi mi o to, czy obniża to szansę, że kompilator ustawia funkcję porównania, czy też powinien być na tyle sprytny, aby zachowywać się dokładnie tak samo, jakby był to typ funkcji lambda, a nie std::function
(wiem, w tym przypadku nie może to być typ lambda, ale wiesz, pytam w ogóle)?
(używam GCC, ale chciałbym wiedzieć, co popularne kompilatory zrobić w ogóle)
Podsumowując, po tym jak dostać wiele świetnych odpowiedzi:
Jeśli prędkość jest krytyczny, najlepiej rozwiązaniem jest użycie klasy z operator()
aka funktor. Najłatwiej jest zoptymalizować kompilator i uniknąć wszelkich pośredników.
Dla łatwiejszej konserwacji i lepszego rozwiązania ogólnego przeznaczenia, przy użyciu funkcji C++ 11, należy użyć std::function
. Jest nadal szybki (tylko trochę wolniejszy od funktora, ale może być pomijalny) i można użyć dowolnej funkcji - std::function
, lambda, dowolnego obiektu wywoływalnego.
Istnieje również opcja użycia wskaźnika funkcji, ale jeśli nie ma problemu z szybkością, myślę, że std::function
jest lepszy (jeśli używasz C++ 11).
Istnieje możliwość zdefiniowania funkcji lambda gdzieś indziej, ale wtedy nic nie zyskujesz z funkcji porównania będącej wyrażeniem lambda, ponieważ równie dobrze możesz uczynić ją klasą z operator()
, a lokalizacja definicji nie będzie i tak ustaw budowę.
Istnieje więcej pomysłów, takich jak korzystanie z delegacji. Jeśli chcesz dokładniej wyjaśnić wszystkie rozwiązania, przeczytaj odpowiedzi :)
Czuję przedwczesną optymalizację. – Fanael
Dlaczego nie po prostu 'bool (*) (int, int)'? Ale bardziej wydajnym rozwiązaniem może być jawna, domyślna klasa orzeczników. –
@Fanael jak byś wiedział, co jeśli mam długi zestaw obiektów renderowanych przez GUI i naprawdę potrzebowałem, aby był tak szybki jak to możliwe – cfa45ca55111016ee9269f0a52e771