2016-07-12 18 views
0

Angenommen, ich habe eine Funktion unique_count, die die Anzahl der eindeutigen Elemente in jedem unsortiert Bereich zählen:zuweisbare Bezug auf beide lvalues ​​und rvalues ​​

template<typename InputIt> 
std::size_t unique_count(InputIt first, InputIt last) 
{ 
    using T = typename std::iterator_traits<InputIt>::value_type; 

    std::vector</* ??? */> v(first, last); 
    std::sort(v.begin(), v.end()); 
    return std::distance(v.begin(), 
         std::unique(v.begin(), v.end())); 
} 

ich eine neue vector, weil ich will nicht Ändern Sie den ursprünglichen Container, aber ich möchte auch nicht unnötig kopieren. Die einfachste Lösung besteht darin, einen Vektor von Zeigern zu erstellen, aber ein Problem ist *first, das entweder const T& (z. B. von vector) oder T (z. B. von einem Strom) zurückgeben kann.

Der /* ??? */ Teil sollte daher konzeptionell const T& entsprechen. Das können wir nicht wirklich machen, da vector s keine Referenzen enthalten können, die nicht zuordenbar sind. Wir können reference_wrapper<const T> auch nicht verwenden, da es nicht aus Provisorien konstruiert werden kann.

Welche Alternativen habe ich?

Antwort

2

Sie wollen /* ??? */ ein Typ sein, der ein T Objekt nicht besitzen kann oder nicht, je nachdem, ob es mit einer temporären T oder const T& errichtet wurde. Aus offensichtlichen Gründen sollten solche Typen im Allgemeinen vermieden werden.

Eine Alternative ist die Verwendung von TAG-Versand oder SFINAE zur Auswahl einer von zwei möglichen Implementierungen, je nachdem, ob *first einen Referenz- oder Nicht-Referenztyp zurückgibt.

Eine weitere Alternative besteht darin, Ihren Algorithmus etwas einzuschränken, so dass er nur Vorwärtsiteratoren akzeptiert. Hier finden Sie garantiert der Lage sein, einfach speichern Iteratoren selbst und nutzen sie, um die Elemente zu vergleichen zeigte auf:

template <typename ForwardIt> 
std::size_t unique_count(ForwardIt first, ForwardIt last) { 
    std::vector<ForwardIt> v; 
    for (auto i = first; i != last; ++i) { 
     v.push_back(i); 
    } 
    const auto pred = [](ForwardIt a, ForwardIt b) { return *a < *b; }; 
    std::sort(v.begin(), v.end(), pred); 
    return std::distance(v.begin(), std::unique(v.begin(), v.end(), pred)); 
} 
+0

Jetzt bin ich mit 'std :: conditional' den Vektorwert Typ zwischen' T' auszuwählen und 'reference_wrapper ' abhängig von 'is_lvalue_reference :: value'. Halten Sie das für einen vernünftigen Ansatz? –

+0

@ZizhengTai Klingt gut für mich. – Brian

Verwandte Themen