2016-05-20 39 views
10

Gli algoritmi standard min e max possono essere confrontati con un singolo valore. Tuttavia, il valore restituito minmax algoritmo non può essere confrontata con una coppia di valori:Confronto di std :: minmax in coppia

#include <algorithm> 
#include <utility> 

template<class T1, class T2> 
constexpr auto make_cref_pair(T1&& t1, T2&& t2) 
{ 
    return std::pair<T1 const&, T2 const&>(std::forward<T1>(t1), std::forward<T2>(t2)); 
} 

int main() 
{ 
    static_assert(std::min(2, 1) == 1); // OK 
    static_assert(std::max(2, 1) == 2); // OK 
    //static_assert(std::minmax(2, 1) == std::make_pair(1, 2)); // ERROR, const int& vs int pair comparison 
    static_assert(std::minmax(2, 1) == std::pair<const int&, const int&>(1, 2)); // OK 
    static_assert(std::minmax(2, 1) == make_cref_pair(1, 2)); // OK 
} 

Live Example

La ragione è che make_pair(2, 1) restituisce un pair<int, int> e minmax(1, 2) restituisce un pair<const int&, const int&>. Non ci sono riferimenti - sovraccarico operator== per pair.

La correzione è quindi di scrivere esplicitamente std::pair<const int&, const int&>(int, int) o di avvolgere questo in una funzione fatta in casa make_cref_pair.

Domande: c'è un modo più pulito per confrontare il valore minmax di ritorno contro un pair di valori? E ho gestito correttamente i riferimenti nel mio make_cref_pair?

+1

temo che 'make_cref_pair' potrebbe non essere legale (prolungamento tempo di vita non si applica agli oggetti secondari, per quanto ne so) – sehe

+0

@sei yikes. Lo stesso vale per la coppia nuda (1,2) '? – TemplateRex

+0

Sarebbe lo stesso. Non ne sono veramente sicuro, ma sembra che ci sia un limite al limite – sehe

risposta

11

std::minmax ha un sovraccarico initializer_list. Questo restituisce una coppia non-const non riferimento:

static_assert(std::minmax({2, 1}) == std::make_pair(1, 2)); 

Purtroppo questo può essere meno efficiente, poiché la complessità sono rispettivamente "esattamente un confronto" e "al massimo (3/2) * t.size() applicazioni corrispondente predicato".

+0

beh, userò il confronto solo in fase di compilazione (è per inizializzare un modello di variabile, da cui il tag C++ 14, ho bisogno di 'constexpr'). Grazie, questa è una bella risposta! – TemplateRex

+0

forse conosci anche la risposta ai problemi della durata usando una 'coppia '? – TemplateRex

+2

@TemplateRex Il problema con i riferimenti ciondolanti è solo un problema se si tenta di accedere 'first' o' second' in seguito. AFAIK questo è un problema con 'minmax' pure. Una soluzione plausibile è usare 'reference_wrapper'. – user6362820

5

Una cosa che si potrebbe fare è sfruttare il sovraccarico std::minmax che prende uno std::initializer_list<T> e restituisce un std::pair<T,T>. Utilizzando che si potrebbe avere

int main() 
{ 
    const int a = 10, b = 20; 
    static_assert(std::minmax({2, 1}) == std::make_pair(1, 2)); 
    static_assert(std::minmax({a, b}) == std::make_pair(a, b)); 
} 

Quali will compile e ti permette di sbarazzarsi di make_cref_pair. Si chiama std::minmax_element quindi non sono sicuro se questo diminuisce l'efficienza o meno.

3

Una possibilità è quella di convertire in modo esplicito il lato sinistro a std::pair<int,int>:

#include <algorithm> 
#include <utility> 

template <typename T1, typename T2> 
constexpr std::pair<T1,T2> myminmax(const T1& t1, const T2& t2) 
{ 
    return std::minmax(t1,t2); 
} 

int main() 
{ 
    static_assert(myminmax(2, 1) == std::make_pair(1, 2)); 
} 
+0

le parentesi elenco inizializzatore sono un modo più conveniente per ottenere questo – TemplateRex

+0

Qualunque sia la variante che funziona meglio per voi. Dipende da te :) – mindriot