O novo <=>
operador torna a escrita de código mais conveniente e pode economizar algum desempenho se o algoritmo de comparação não for trivial, porque não precisa ser repetido duas vezes para obter a ordem completa.
Ou pelo menos pensei assim quando soube disso. Porém, quando tento usar na prática, em um switch
depoimento, não funciona.
Este código não compila:
#include <iostream>
void compare_values(int x, int y)
{
switch (x <=> y)
{
case std::strong_ordering::less:
std::cout << "is less\n";
break;
case std::strong_ordering::greater:
std::cout << "is greater\n";
break;
case std::strong_ordering::equal:
std::cout << "is equal\n";
break;
}
}
O compilador mostra um erro sugerindo que o valor retornado por <=>
não pode ser usado em a switch
:
<source>: In function 'void compare_values(int, int)':
<source>:5:15: error: switch quantity not an integer
5 | switch (x <=> y)
| ~~^~~~~
Compiler returned: 1
( exemplo ao vivo )
Eu acho que usar o operador de nave espacial no switch é um caso de uso bastante básico, óbvio e comum, então provavelmente existe algum truque para fazê-lo funcionar. Eu não consigo entender, no entanto.
Como posso corrigir esse código?
O problema é que o operador nave espacial (formalmente conhecido como comparação de três vias ) não retorna um tipo ingeral e, portanto, não pode ser usado em uma
switch-case
instrução.Neste caso de comparação de tipos como
int
s, o operador nave espacial retorna astd::strong_ordering
.(Uma observação lateral: como você pode ver na documentação, há casos em que o operador da nave espacial retorna a,
std::partial_ordering
mas este também não é um tipo integral).Você pode usá-lo em uma
if-else
declaração.Se preferir usar a
switch-case
, você pode usar um utilitário trivial que converte thestd::strong_ordering
em um tipo integral com alguns valores predefinidos.Retornar -1/0/1 neste caso será bastante natural:
Saída:
Demonstração ao vivo
Os compiladores fazem um péssimo trabalho ao otimizar os métodos if (gcc/clang/MSVC). A melhor maneira de obter um bom codegen é brincar com as 3 grandes implementações usando um membro de valor char subjacente. Pode-se facilmente adicionar static_asserts com os valores strong_ordering/weak_ordering para garantir isso. O seguinte irá otimizar para, na pior das hipóteses, uma cópia. A única desvantagem é que se perde a nomenclatura explícita, mas é possível adicionar ainda uma classe enum/enum como valor de retorno.