2013-05-26 13 views
13

Stavo guardando std :: unordered_map e ho visto che se volevo usare una stringa come chiave, dovevo creare una classe contenente un functor.È possibile utilizzare una funzione lambda per un parametro template?

Per curiosità, mi chiedevo se un lambda potesse essere usato al posto di questo.

Ecco l'originale lavoro:

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

Ecco il mio tentativo:

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

che non è riuscito con i seguenti errori:

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’ 

Attribuite gli errori, sembrerebbe che la lamba è abbastanza diverso da un functor che non lo rende un'espressione costante. È corretto?

+2

'std :: hash' è specializzato per' std :: string', non è necessario fornire qualcosa da soli se non si desidera migliorare/modificare l'hash. Inoltre, pensa a quello che stai facendo: 'std :: unordered_map' si aspetta un * tipo * come argomento del template, e un'espressione lambda è esattamente quella - un'espressione, cioè un valore, * non * un tipo. – Xeo

+0

Ho trovato che nel compilatore g ++ stavo usando (v4.5.3 con -std = gnu ++ 0x), mi avrebbe dato un sacco di errori se non avessi specificato la funzione hash quando usavi una chiave stringa. – Adrian

+0

Per quanto riguarda l'espressione, sì, credo che sarebbe la risposta. – Adrian

risposta

12

Il modo per superare la funzione lambda è:

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

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

L'uscita di decltype(hf) è un tipo di classe che non ha costruttore di default (è eliminato da =delete). Quindi, è necessario passare l'oggetto dal costruttore di unordered_map per consentirgli di costruire l'oggetto lambda.

+1

@MM., Come questo: 'std :: unordered_map m (1, hf);'. Il primo argomento è il conteggio iniziale del secchio, il secondo è l'hasher. In questo caso non è possibile utilizzare l'inizializzazione delle parentesi, purtroppo. – avakar

+0

Interessante, anche se è un po 'un inganno dato che non si sta solo passando la funzione lambda come parametro template. Infatti, il parametro template può essere evitato tutti insieme tramite una funzione template helper come: 'template auto make_unordered_map (size_t bucketCount, HASHER const & hf) -> unordered_map { return unordered_map (bucketCount, hf); } 'come visto [qui] (http://ideone.com/62heUn). Comunque, è interessante. :) – Adrian

Problemi correlati