Comparando duas instâncias da estrutura a seguir, recebo um erro:
struct MyStruct1 {
MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
my_struct_2(_my_struct_2),
an_int(_an_int)
{}
std::string toString() const;
MyStruct2 my_struct_2;
int an_int;
};
O erro é:
erro C2678: binário '==': nenhum operador encontrado, o que leva um operando à esquerda do tipo 'myproj :: MyStruct1' (ou não há conversão aceitável)
Por quê?
c++
struct
comparison-operators
Jonathan
fonte
fonte
struct
s por igualdade? E se você quiser a maneira mais simples, semprememcmp
há tanto tempo que suas estruturas não contêm ponteiro.memcmp
falha com membros não POD (comostd::string
) e estruturas preenchidas.==
operador --- com uma semântica que quase nunca é a desejada. (E eles não fornecem um meio de substituí-la, então você acaba tendo que usar uma função de membro). As linguagens "modernas" que conheço também não fornecem semântica de valor, então você é forçado a usar ponteiros, mesmo quando eles não são apropriados.operator=
(mesmo que freqüentemente faça a coisa errada), por razões de compatibilidade com C. A compatibilidade com C não requer umoperator==
. Globalmente, eu prefiro o que C ++ faz ao que Java faz. (Não sei C #, então talvez seja melhor.)= default
!C ++ 20 introduziu comparações padrão, também conhecidas como "nave espacial"
operator<=>
, que permite que você solicite<
/<=
/==
/!=
/>=
/ e / ou>
operadores gerados pelo compilador com a implementação óbvia / ingênua (?) ...... mas você pode personalizar isso para situações mais complicadas (discutido abaixo). Veja aqui a proposta de idioma, que contém justificativas e discussão. Esta resposta continua relevante para C ++ 17 e anteriores e para uma visão de quando você deve personalizar a implementação de
operator<=>
....Pode parecer um pouco inútil para C ++ não ter padronizado isso anteriormente, mas muitas vezes structs / classes têm alguns membros de dados para excluir da comparação (por exemplo, contadores, resultados em cache, capacidade do contêiner, código de sucesso / erro da última operação, cursores), como bem como decisões a tomar sobre uma miríade de coisas, incluindo, mas não se limitando a:
int
membro específico pode eliminar 99% dos objetos desiguais muito rapidamente, enquanto ummap<string,string>
membro pode muitas vezes ter entradas idênticas e ser relativamente caro para comparar - se os valores são carregados em tempo de execução, o programador pode ter insights sobre o compilador não podevector
,list
) e, em caso afirmativo, se não há problema em classificá-los no local antes de comparar vs. usar memória extra para classificar temporários cada vez que uma comparação é feitaunion
a compararoperator==
se implementam (mas podem tercompare()
ouoperator<
oustr()
ou getters ...)Portanto, é bom ter um erro até que você tenha pensado explicitamente sobre o que a comparação deve significar para sua estrutura específica, em vez de deixá-la compilar, mas não fornecer um resultado significativo em tempo de execução .
Dito isso, seria bom se C ++ lhe permitisse dizer
bool operator==() const = default;
quando você decidiu que um==
teste membro por membro "ingênuo" estava ok. O mesmo para!=
. Dado vários membros / bases, "default"<
,<=
,>
, e>=
implementações parecer impossível embora - em cascata com base na ordem de do possível, mas muito improvável que seja o que queria, dada conflitantes imperativos de ordenamento membro (bases de ser, necessariamente, antes de os membros, agrupando por declaração acessibilidade, construção / destruição antes do uso dependente). Para ser mais amplamente útil, C ++ precisaria de um novo membro de dados / sistema de anotação de base para orientar as escolhas - isso seria ótimo ter no Padrão, no entanto, idealmente acoplado com geração de código definido pelo usuário baseado em AST ... Espero isto'Implementação típica de operadores de igualdade
Uma implementação plausível
É provável que uma implementação razoável e eficiente seja:
Observe que isso também precisa de um
operator==
paraMyStruct2
.As implicações desta implementação, e alternativas, são discutidas sob o título Discussão das especificações de seu MyStruct1 abaixo.
Uma abordagem consistente para ==, <,> <= etc
É fácil alavancar
std::tuple
os operadores de comparação para comparar suas próprias instâncias de classe - use apenasstd::tie
para criar tuplas de referências a campos na ordem de comparação desejada. Generalizando meu exemplo a partir daqui :Quando você "possui" (ou seja, pode editar, um fator com bibliotecas corporativas e de terceiros) a classe que deseja comparar, e especialmente com a preparação do C ++ 14 para deduzir o tipo de retorno de função da
return
instrução, geralmente é melhor adicionar um " vincule a "função de membro à classe que você deseja comparar:Então, as comparações acima simplificam para:
Se você quiser um conjunto mais completo de operadores de comparação, sugiro operadores boost (pesquisar por
less_than_comparable
). Se não for adequado por algum motivo, você pode ou não gostar da ideia de macros de suporte (online) :... que pode então ser usado a la ...
(Versão C ++ 14 vinculado a membros aqui )
Discussão dos detalhes de sua MyStruct1
Existem implicações na escolha de fornecer um membro independente versus um membro
operator==()
...Implementação autônoma
Você tem uma decisão interessante a tomar. Como sua classe pode ser construída implicitamente a partir de um
MyStruct2
, uma função independente / não membrobool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
suportaria ...... criando primeiro um de temporário
MyStruct1
emy_myStruct2
, em seguida, fazendo a comparação. Isso definitivamente deixariaMyStruct1::an_int
definido para o valor do parâmetro padrão do construtor de-1
. Dependendo se você incluiran_int
comparação na implementação do seuoperator==
, umMyStruct1
pode ou não comparar igual a umaMyStruct2
que se compara igual aoMyStruct1
domy_struct_2
membro! Além disso, criar um temporárioMyStruct1
pode ser uma operação muito ineficiente, pois envolve a cópia domy_struct2
membro existente para um temporário, apenas para descartá-lo após a comparação. (Claro, você poderia evitar esta construção implícita deMyStruct1
s para comparação, tornando esse construtorexplicit
ou removendo o valor padrão paraan_int
.)Implementação de membro
Se você quiser evitar a construção implícita de a
MyStruct1
de aMyStruct2
, torne o operador de comparação uma função-membro:Observe a
const
palavra-chave - necessária apenas para a implementação do membro - avisa o compilador que a comparação de objetos não os modifica, portanto, pode ser permitida emconst
objetos.Comparando as representações visíveis
Às vezes, a maneira mais fácil de obter o tipo de comparação que deseja pode ser ...
... o que geralmente é muito caro também - aqueles
string
são criados dolorosamente para serem jogados fora! Para tipos com valores de ponto flutuante, comparar representações visíveis significa que o número de dígitos exibidos determina a tolerância dentro da qual valores quase iguais são tratados como iguais durante a comparação.fonte
int cmp(x, y)
oucompare
função que retorna um valor negativo parax < y
, 0 para a igualdade e um valor positivo parax > y
é usado como base para<
,>
,<=
,>=
,==
, e!=
; é muito fácil usar o CRTP para injetar todos esses operadores em uma classe. Tenho certeza de que postei a implementação em uma resposta antiga, mas não consegui encontrar rapidamente.>
,<=
e>=
em termos de<
. Você também poderia implementar==
e!=
dessa forma, mas isso geralmente não seria uma implementação muito eficiente, eu acho. Seria bom se nenhum CRTP ou outros truques fossem necessários para tudo isso, mas o padrão apenas obrigaria a autogeração desses operadores se não fosse explicitamente definido pelo usuário e<
fosse definido.==
e!=
não pode ser eficientemente expresso usando<
que o uso de comparar para tudo é comum. "Seria bom se não CRTP ou outros truques seriam necessários" - talvez, mas, em seguida, CRTP pode ser facilmente usado para gerar lotes de outros operadores (por exemplo, bit a bit|
,&
,^
de|=
,&=
e^=
,+
-
*
/
%
a partir de suas formas de atribuição; binário-
de negação unário e+
) - tantas variações potencialmente úteis sobre este tema que apenas fornecer um recurso de linguagem para uma parte bastante arbitrária disso não é particularmente elegante.std::tie
para fazer a comparação de vários membros?Você precisa definir explicitamente
operator ==
paraMyStruct1
.Agora a comparação == é válida para 2 desses objetos.
fonte
Iniciando em C ++ 20, deve ser possível adicionar um conjunto completo de operadores de comparação padrão (
==
,<=
, etc.) para uma classe declarando uma de três vias operador de comparação padrão ( "nave espacial" operador), como este:Com um compilador C ++ 20 compatível, adicionar essa linha a MyStruct1 e MyStruct2 pode ser suficiente para permitir comparações de igualdade, presumindo que a definição de MyStruct2 seja compatível.
fonte
A comparação não funciona em estruturas em C ou C ++. Em vez disso, compare por campos.
fonte
Por padrão, as estruturas não têm um
==
operador. Você terá que escrever sua própria implementação:fonte
Por padrão, o operador == funciona apenas para primitivos. Para fazer seu código funcionar, você precisa sobrecarregar o operador == para sua estrutura.
fonte
Porque você não escreveu um operador de comparação para sua estrutura. O compilador não o gera para você, portanto, se você deseja comparação, deve escrevê-lo você mesmo.
fonte