2016-05-23 15 views
5

Was ist die kanonische Art, einen Wert zu aktualisieren (mit einem Schlüssel und einem neuen Wert) in einem boost::hana::map?Kanonischer Weg zum Aktualisieren/Ersetzen eines Kartenwerts in `boost :: hana :: map`

Ich versuchte boost::hana::replace_if verwenden, aber es auf map funktioniert nicht, da es keine Functor ist - ich habe es durch die Umwandlung der map zu einem tuple und dann zurück zu einem map zu arbeiten, aber es klingt ineffizient.

Die Alternative, die ich derzeit verwende, ruft map::erase_key gefolgt von map::insert.

Gibt es eine replace oder update Funktion für diesen Zweck entwickelt, die ich vermisse? Oder ist das die "kanonische" Art, einen Wert zu aktualisieren?

Antwort

4

Ich glaube nicht, dass es derzeit einen kanonischen Weg gibt, dies zu tun. Wenn es gültige Anwendungsfälle dafür gibt, könnten wir vielleicht eine Funktion zur Unterstützung erhalten. Das Problem mit hana::erase_key ist, dass Sie eine neue Karte erstellen und dann erneut mit hana::insert. Vorläufig ist es wahrscheinlich am besten, hana::unpack zu verwenden und dann eine neue Karte zu erstellen.

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

Auf einer anderen Anmerkung, sollte vielleicht hana::map ein Functor sein.

+2

Ich glaube, du brauchst deine 'hana :: hash (hana :: erste (neue_pair)) == hana :: hash (hana :: erste (p))' test zu sein 'hana :: equal (hana :: zuerst (neues_Paar), hana :: erstes (p)) '. Wenn Sie andernfalls den Wert eines Schlüssels ersetzen, dessen Hash mit einem anderen Schlüssel in der Map kollidiert, ersetzen Sie den Wert für alle Schlüssel, die denselben Hashwert haben, auch wenn die Schlüssel unterschiedlich sind. Im Grunde ersetzen Sie den Wert für alle Schlüssel in demselben Bucket. Und ein Nitpick, aber mit 'hana :: equal' könnte besser sein als' == 'für generischen Code, weil es mit z. 'std :: integral_constant'. –

+1

Ah, das stimmt. Ich habe mein Beispiel korrigiert und auch den Typ des Werts geändert, um zu zeigen, dass der Wert nicht einfach mutiert wird. –

2

Müssen Sie den Typ des Werts ändern? Wenn nicht, und wenn Ihr Wert zugewiesen werden kann, können Sie oder äquivalent hana::at_key(map, key) = new_value verwenden, da hana::at_key eine Referenz zurückgibt.

Wenn Sie den Typ des Werts ändern möchten, ist das schwieriger. Wir werden nichts in-place tun können, da der Typ der Map nach dem Ersetzen des Werts sich von dem Typ unterscheidet, bevor der Wert ersetzt wird. Daher müssen wir eine neue Karte oder eine modifizierte Ansicht dieser Karte erstellen (aber Ansichten werden derzeit nicht unterstützt). Die Verwendung von erase_key und insert wird tatsächlich dazu führen, dass zwei Karten erstellt werden, was ineffizient ist. Stattdessen könnten wir eine Art von update Funktion bereitstellen, die das gleiche erreichen würde, aber nur eine Kopie der Karte erstellen würde (das Ergebnis). Ich glaube, wir könnten auch besser als erase_key + insert in Bezug auf die Zusammenstellung Zeiten durch Bereitstellung unserer eigenen Funktion. Ich öffnete this issue, um Ihre Anfrage zu verfolgen, da ich denke, dass es wichtig ist, so etwas zu bieten; Vielen Dank.

Schließlich möchte ich einen Kommentar abgeben, was Jason sagte:

Auf einer anderen Anmerkung, vielleicht hana :: Karte sollte ein Functor sein.

hana::map könnte Functor gemacht werden, aber ich bin mir nicht sicher, dass transform die Schlüssel der Karte berühren könnte, während immer noch die Functor Gesetze zu respektieren. Wenn das nicht der Fall ist, könnten Sie immer noch nicht sagen "Ersetzen Sie den Wert mit XXX, wenn der Schlüssel ein Prädikat erfüllt" z. hana::replace_if. Ich habe versucht (aber bisher fehlgeschlagen), ein Beispiel für Funktionen zu finden, die die Gesetze brechen würden, wenn die Reihenfolge der zugrundeliegenden Schlüssel/Wert-Paare grundlegend transformiert würde, aber meine Intuition ist, dass es möglich ist, ein solches Beispiel zu finden. Wird in Ausgabe # 278 fortgesetzt.