2016-05-23 28 views
5

Qual è il modo canonico di aggiornare un valore (dato una chiave e un nuovo valore) all'interno di un boost::hana::map?modo canonico di aggiornamento/sostituzione di un valore mappa in `boost :: :: hana map`

Ho provato ad utilizzare boost::hana::replace_if ma non funziona su map in quanto non è un Functor - posso farlo funzionare convertendo l'map ad un tuple e poi di nuovo ad un map, ma suona inefficiente.

L'alternativa che sto utilizzando attualmente è map::erase_key seguita da map::insert.

Esiste una funzione replace o update progettata per questo scopo che potrebbe mancare? O è questo il modo "canonico" di aggiornare un valore?

risposta

4

Non penso che al momento ci sia un modo canonico per farlo. Se ci sono casi d'uso validi per questo, forse potremmo ottenere una funzione in là per supportarlo. Il problema con hana::erase_key consiste nel fatto che creerai una nuova mappa e poi di nuovo con hana::insert. Per il momento, usare hana::unpack e quindi creare una nuova mappa è probabilmente la scelta migliore.

#include <boost/hana.hpp> 

namespace hana = boost::hana; 

template <typename NewPair> 
struct replace_helper_t 
{ 
    NewPair const& new_pair; 

    template <typename Pair> 
    constexpr decltype(auto) operator()(Pair&& p) const 
    { 
    return hana::if_(
     hana::equal(hana::first(new_pair), hana::first(p)), 
     new_pair, 
     std::forward<Pair>(p) 
    ); 
    } 
}; 

struct replace_t 
{ 
    template <typename Map, typename NewPair> 
    constexpr auto operator()(Map&& m, NewPair&& new_pair) const 
    { 
    return hana::unpack(std::forward<Map>(m), 
     hana::on(
     hana::make_map, 
     replace_helper_t<NewPair>{std::forward<NewPair>(new_pair)} 
    ) 
    ); 
    } 
}; 

constexpr replace_t replace{}; 

int main() 
{ 
    auto my_map = hana::make_map(
    hana::make_pair(hana::int_c<7>, 7), 
    hana::make_pair(hana::int_c<13>, 13), 
    hana::make_pair(hana::int_c<23>, 23) 
); 

    auto new_map = replace(my_map, hana::make_pair(hana::int_c<13>, 14.0f)); 

    BOOST_HANA_RUNTIME_ASSERT(new_map == 
    hana::make_map(
     hana::make_pair(hana::int_c<7>, 7), 
     hana::make_pair(hana::int_c<13>, 14.0f), 
     hana::make_pair(hana::int_c<23>, 23) 
    ) 
); 
} 

In un'altra nota, forse hana::map dovrebbe essere un Functor.

+2

Credo che tu abbia bisogno del tuo 'hana :: hash (hana :: first (new_pair)) == hana :: hash (hana :: first (p))' test per essere 'hana :: equal (hana :: primo (new_pair), hana :: first (p)) '. Altrimenti, se sostituisci il valore associato a una chiave il cui hash si scontra con qualsiasi altra chiave nella mappa, sostituirai il valore di tutte le chiavi che condividono lo stesso hash anche se le chiavi sono diverse. Fondamentalmente sostituirai il valore di tutte le chiavi nello stesso bucket. E un nitpick, ma usare 'hana :: equal' potrebbe essere migliore di' == 'per il codice generico perché funzionerà con, ad es. 'Std :: integral_constant'. –

+1

Ah, giusto. Ho corretto il mio esempio e modificato anche il tipo del valore per dimostrare che non si tratta semplicemente di mutare il valore. –

2

È necessario modificare il tipo di valore? In caso contrario, e se è possibile assegnare il valore, è possibile utilizzare map[key] = new_value o equivalentemente hana::at_key(map, key) = new_value, poiché hana::at_key restituisce un riferimento.

Se è necessario il tipo di valore da modificare, è più difficile. Non saremo in grado di fare nulla sul posto, perché il tipo di mappa dopo la sostituzione del valore sarà diverso dal suo tipo prima di sostituire il valore. Quindi, dobbiamo creare una nuova mappa o qualche tipo di vista modificata di quella mappa (ma le viste non sono attualmente supportate). L'utilizzo di erase_key e insert causerà effettivamente la creazione di due mappe, il che è inefficiente. Invece, potremmo fornire qualche tipo di funzione update che otterrebbe lo stesso, ma creerebbe solo una copia della mappa (il risultato). Credo che potremmo fare anche meglio di erase_key + insert in termini di tempi di compilazione fornendo la nostra funzione. Ho aperto this issue per tenere traccia della tua richiesta, poiché penso che sia importante fornire qualcosa di simile; Grazie.

Infine, vorrei commentare quello che ha detto Jason:

In un'altra nota, forse hana :: mappa dovrebbe essere un funtore.

hana::map potrebbe essere fatto un funtore, ma non sono sicuro che transform potrebbe toccare i tasti della mappa, pur nel rispetto delle leggi funtore. Se così non fosse, non si sarebbe ancora in grado di dire "sostituire il valore con XXX se la chiave soddisfa qualche predicato" usando ad es. hana::replace_if. Ho provato (ma non sono riuscito finora) a trovare un esempio di funzioni che infrangerebbero le leggi se lo hana::transform trasformasse sostanzialmente la sequenza di coppie chiave/valore sottostanti, ma la mia intuizione è che è possibile trovare un tale esempio. Continua nel numero # 278.