2013-05-26 14 views
13

Patrzyłem na std :: unordered_map i zobaczyłem, że jeśli chciałbym użyć ciągu jako klucza, musiałbym utworzyć klasę zawierającą funktora.Czy można użyć funkcji lambda dla parametru szablonu?

Z ciekawości zastanawiałem się, czy zamiast tego można użyć lambda.

Oto praca oryginalna:

struct hf 
{ 
    size_t operator()(string const& key) const 
    { 
    return key[0]; // some bogus simplistic hash. :) 
    } 
} 

std::unordered_map<string const, int, hf> m = {{ "a", 1 }}; 

Oto moja próba:

std::unordered_map<string const, int, [](string const& key) ->size_t {return key[0];}> m = {{ "a", 1 }}; 

To nie powiodło się z następujących błędów:

exec.cpp: In lambda function: 
exec.cpp:44:77: error: ‘key’ cannot appear in a constant-expression 
exec.cpp:44:82: error: an array reference cannot appear in a constant-expression 
exec.cpp: At global scope: 
exec.cpp:44:86: error: template argument 3 is invalid 
exec.cpp:44:90: error: invalid type in declaration before ‘=’ token 
exec.cpp:44:102: error: braces around scalar initializer for type ‘int’ 

Given błędy, wydaje się, że lamba jest na tyle różna od funktora, że ​​nie jest stałą ekspresją. Czy to jest poprawne?

+2

'std :: hash' specjalizuje się w' std :: string', nie ma potrzeby dostarczania czegoś samemu, jeśli nie chcesz poprawić/zmienić hasza. Pomyśl także o tym, co robisz: 'std :: unordered_map' oczekuje, że * typ * jest argumentem szablonu, a wyrażenie lambda jest dokładnie tym - wyrażeniem, tj. Wartością, * nie * typem. – Xeo

+0

Znalazłem, że w kompilatorze g ++, którego używałem (v4.5.3 z opcją -std = gnu ++ 0x), dałoby mi to mnóstwo błędów, gdybym nie określił funkcji skrótu przy użyciu klucza łańcucha. – Adrian

+0

Co do tego, że jest to wyrażenie, tak, myślę, że to byłaby odpowiedź. – Adrian

Odpowiedz

12

Sposób przekazać funkcję lambda jest:

auto hf = [](string const& key)->size_t { return key[0]; }; 

unordered_map<string const, int, decltype(hf)> m (1, hf); 
           ^^^^^^^^^^^^  ^^ 
           passing type  object 

Wyjście decltype(hf) jest typem klasy, który nie ma domyślnego konstruktora (nie jest to usunięty przez =delete). Tak więc musisz przekazać obiekt przez konstruktor z unordered_map, aby umożliwić skonstruowanie obiektu lambda.

+1

@MM., Tak: 'std :: unordered_map m (1, hf);'. Pierwszy argument to początkowa liczba wiaderek, a druga to wartość mieszająca. W tym przypadku nie można używać inicjalizacji nawiasów, niestety. – avakar

+0

Interesujące, choć trochę oszustwo, ponieważ nie przekazujesz tylko funkcji lambda jako parametru szablonu. W rzeczywistości można uniknąć całego parametru szablonu za pomocą funkcji szablonu pomocnika, np .: 'szablon auto make_unordered_map (size_t bucketCount, HASHER const i hf) -> unordered_map { return unordered_map (bucketCount, hf); } 'jak widać [tutaj] (http://ideone.com/62heUn). Wciąż jest to interesujące. :) – Adrian

Powiązane problemy