Perché è stato introdotto std :: range :: less?

Aug 15 2020

Su cppreference sustd::ranges::less , nelle note possiamo vedere che:

A differenza std::less, std::ranges::lessrichiede che tutti i sei operatori di confronto <, <=, >, >=, ==e !=di essere valido (attraverso il totally_ordered_withvincolo).

Ma perché? Perché dovremmo usare std::ranges::less{}invece di std::less{}? Qual è la situazione pratica in cui ci si vuole less{}solo se sono definiti altri operatori di confronto, non solo <quello?

Risposte

5 NicolBolas Aug 15 2020 at 12:13

Qual è la situazione pratica in cui vogliamo less {} solo se sono definiti altri operatori di confronto, non solo quello <?

Non tutto ciò che riguarda la libreria Ranges si basa esclusivamente su ciò che è "pratico". Si tratta in gran parte di rendere logico il linguaggio e la libreria.

I concetti come funzionalità del linguaggio offrono alla libreria standard l'opportunità di definire combinazioni significative di caratteristiche degli oggetti. Dire che un tipo ha un operator<è utile dal punto di vista puramente pratico di dirti quali operazioni sono disponibili per esso. Ma in realtà non dice nulla di significativo sul tipo.

Se un tipo è totalmente ordinato, logicamente significa che è possibile utilizzare uno qualsiasi degli operatori di confronto per confrontare due oggetti di quel tipo. Sotto l'idea di un ordine totale, a < be b > asono dichiarazioni equivalenti. Quindi ha senso che se il codice è limitato ai tipi che forniscono un ordine totale, a quel codice dovrebbe essere consentito di utilizzare entrambe le istruzioni.

ranges::less::operator()non utilizza alcun operatore diverso da <. Ma questa funzione è limitata ai tipi che modellano il totally_orderedconcetto. Questo vincolo esiste perché ranges::lessè a questo scopo : confrontare tipi che sono totalmente ordinati. Potrebbe avere un vincolo più ristretto, ma ciò significherebbe gettare via qualsiasi significato fornito dall'ordinamento totale.

Inoltre, impedisce di esporre agli utenti dettagli di implementazione arbitrari. Ad esempio, supponiamo di avere un modello che accetta un tipo Te che desideri utilizzare Tin un'operazione ranges::lessbasata su. Se vincoli questo modello ad avere solo un operator<, allora hai effettivamente messo la tua implementazione nel vincolo. Non hai più la libertà di passare ranges::greaterinternamente all'implementazione . Considerando che se avessi messo i std::totally_orderedtuoi vincoli, avresti chiarito all'utente ciò che deve fare mentre ti concedi la libertà di usare qualsiasi funtore di cui hai bisogno.

E poiché operator<=>esiste e semplifica l'implementazione degli operatori di ordinazione in un'unica funzione, non ci sono svantaggi pratici . Bene, ad eccezione del codice che deve essere compilato sia in C ++ 17 che in C ++ 20.

In sostanza, non dovresti scrivere tipi "ordinati" semplicemente scrivendo operator<per cominciare.

1 Kyle Aug 15 2020 at 09:20

Per quanto posso dire in base alla proposta l'idea è semplicemente di semplificare il design degli oggetti funzione. std::lessè una classe template che richiede un parametro template e rappresenta un confronto omogeneo. Questo parametro del modello può essere omesso per impostazione predefinita, il std::less<void>che consente confronti eterogenei. L'argomento sembra essere che il caso omogeneo non è necessario in quanto viene gestito correttamente dall'approccio eterogeneo, quindi il design può essere notevolmente semplificato e un modello di classe non è affatto necessario.

Quanto al motivo per cui operator<sono richiesti gli altri operatori, non sono completamente sicuro. La mia ipotesi migliore è che questa sia solo una parte di ciò che significa avere un ordine totale definito in C ++ tra due tipi, possibilmente diversi.