C ++ 20 ,operator<=>
derleyici tarafından oluşturulan <
/ <=
/ ==
/ !=
/ >=
/ ve / veya >
işleçleri bariz / naif (?) Uygulama ile talep etmenize olanak tanıyan "uzay gemisi" olarak adlandırılan varsayılan karşılaştırmaları tanıttı ...
auto operator<=>(const MyClass&) const = default;
... ancak bunu daha karmaşık durumlar için özelleştirebilirsiniz (aşağıda tartışılmıştır). Gerekçeler ve tartışma içeren dil önerisi için buraya bakın . Bu cevap, C ++ 17 ve öncesi için ve operator<=>
...
Bunu daha önce Standartlaştırmamış olmak C ++ 'ın biraz yararsız görünebilir, ancak genellikle yapıların / sınıfların karşılaştırmanın dışında tutacakları bazı veri üyeleri vardır (örn. Sayaçlar, önbelleğe alınan sonuçlar, konteyner kapasitesi, son işlem başarısı / hata kodu, imleçler) ve bunlarla sınırlı olmamak üzere sayısız şey hakkında alınacak kararlar :
- ilk önce hangi alanların karşılaştırılacağı, örneğin belirli bir
int
üyeyi karşılaştırmak eşit olmayan nesnelerin% 99'unu çok hızlı bir şekilde ortadan kaldırabilirken, bir map<string,string>
üye genellikle aynı girdilere sahip olabilir ve karşılaştırmak nispeten pahalı olabilir - değerler çalışma zamanında yüklenirse, programcı derleyici olamaz
- dizeleri karşılaştırmada: büyük / küçük harf duyarlılığı, boşluk ve ayırıcıların denkliği, kaçış kuralları ...
- kayan / çiftleri karşılaştırırken hassasiyet
- NaN kayan nokta değerlerinin eşit kabul edilip edilmeyeceği
- işaretçileri veya veriye işaret edenleri karşılaştırma (ve eğer ikincisi ise, işaretçilerin diziler için olup olmadığını ve karşılaştırmaya ihtiyaç duyan kaç nesne / bayt olduğunu nasıl anlarsınız)
- Sıralanmamış kapları karşılaştırırken sıralamanın önemli olup olmadığı (örn
vector
. list
) ve öyleyse, karşılaştırma yapmadan önce bunları yerinde sıralamanın uygun olup olmadığı, her karşılaştırma yapıldığında geçici değerleri sıralamak için ekstra bellek kullanmanın uygun olup olmadığı
- Şu anda kaç dizi öğesi karşılaştırılması gereken geçerli değerleri tutuyor (bir yerde veya bir gözcü boyut var mı?)
union
karşılaştırılacak bir üye
- normalleştirme: örneğin, tarih türleri aralık dışı güne veya yılın ayına izin verebilir veya bir rasyonel / kesir nesnesi 6 / 8'ine sahipken diğerinde 3 / 4ers olabilir, bu performans nedenleriyle düzeltir ayrı bir normalleştirme adımı ile tembel olarak; karşılaştırmadan önce normalleşmeyi tetikleyip tetiklemeyeceğinize karar vermeniz gerekebilir
- zayıf işaretçiler geçerli olmadığında ne yapmalı
operator==
Kendilerini uygulamayan (ancak compare()
veya operator<
veya str()
veya alıcılara sahip olabilen ...) üyeler ve üsler nasıl ele alınır
- diğer iş parçacıklarının güncellemek isteyebileceği verileri okurken / karşılaştırırken hangi kilitler alınmalıdır?
Bu nedenle, karşılaştırmanın derlemesine izin vermek, ancak çalışma zamanında size anlamlı bir sonuç vermemesi yerine , belirli yapınız için ne anlama gelmesi gerektiğini açıkça düşünene kadar bir hata olması güzel .
C Eğer diyelim ++ eğer söyledi Bütün bunlar, iyi olurdu bool operator==() const = default;
bir "naif" üye bazında üyesi karar vermiştim zaman ==
testi oldu Tamam. Aynı !=
. Verilen çoklu üyeleri / bazlar, "varsayılan" <
, <=
, >
, ve >=
uygulamalar umutsuz olsa görünüyor - beyanı olası ama, istediği göre gruplama, bazlar üyeleri önce mutlaka olmak (üye sipariş için zorunlulukları çelişkili verilen ne olduğunu düşünmek için pek sırasına göre basamaklı erişilebilirlik, yapım / yıkımdan önce bağımlı kullanım). Daha yaygın bir şekilde kullanışlı olması için, C ++, seçimleri yönlendirmek için yeni bir veri üyesine / temel açıklama sistemine ihtiyaç duyacaktır - bu, Standartta olması harika bir şey olurdu, ideal olarak AST tabanlı kullanıcı tanımlı kod oluşturma ile birleşti ... o'
Eşitlik operatörlerinin tipik uygulaması
Makul bir uygulama
Bu var olasılıkla makul ve etkili uygulama olacağını:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.my_struct2 == rhs.my_struct2 &&
lhs.an_int == rhs.an_int;
}
Bunun operator==
için MyStruct2
de gerekli olduğunu unutmayın .
Bu uygulamanın etkileri ve alternatifleri, aşağıdaki MyStruct1 cihazınızın özelliklerinin tartışılması başlığı altında tartışılmaktadır .
==, <,> <= vb. İçin tutarlı bir yaklaşım
std::tuple
Kendi sınıf örneklerinizi karşılaştırmak için karşılaştırma işleçlerinden yararlanmak kolaydır - sadece std::tie
istenen karşılaştırma sırasına göre alanlara referans demetleri oluşturmak için kullanın . Örneğimi buradan genellemek :
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) ==
std::tie(rhs.my_struct2, rhs.an_int);
}
inline bool operator<(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) <
std::tie(rhs.my_struct2, rhs.an_int);
}
Karşılaştırmak istediğiniz sınıfa "sahip olduğunuzda" (yani, kurumsal ve üçüncü taraf kitaplarla bir faktör düzenleyebildiğinizde) ve özellikle C ++ 14'ün ifadeden işlev dönüş türünü çıkarmaya hazır olması durumunda return
, genellikle bir " "üye işlevini, karşılaştırabilmek istediğiniz sınıfa bağlayın:
auto tie() const { return std::tie(my_struct1, an_int); }
Daha sonra yukarıdaki karşılaştırmalar şu şekilde basitleşir:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.tie() == rhs.tie();
}
Daha kapsamlı bir karşılaştırma operatörü seti istiyorsanız, operatörleri artırmanızı öneririm (arayın less_than_comparable
). Herhangi bir nedenle uygun değilse, destek makroları fikrini beğenebilir veya beğenmeyebilirsiniz (çevrimiçi) :
#define TIED_OP(STRUCT, OP, GET_FIELDS) \
inline bool operator OP(const STRUCT& lhs, const STRUCT& rhs) \
{ \
return std::tie(GET_FIELDS(lhs)) OP std::tie(GET_FIELDS(rhs)); \
}
#define TIED_COMPARISONS(STRUCT, GET_FIELDS) \
TIED_OP(STRUCT, ==, GET_FIELDS) \
TIED_OP(STRUCT, !=, GET_FIELDS) \
TIED_OP(STRUCT, <, GET_FIELDS) \
TIED_OP(STRUCT, <=, GET_FIELDS) \
TIED_OP(STRUCT, >=, GET_FIELDS) \
TIED_OP(STRUCT, >, GET_FIELDS)
... bu daha sonra bir la kullanılabilir ...
#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int
TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)
(C ++ 14 üye bağlı sürümü burada )
MyStruct1 cihazınızın özelliklerinin tartışılması
Bağımsız üyeye karşı bağımsız olma seçiminin çıkarımları vardır operator==()
...
Bağımsız uygulama
İlginç bir karar vermen gerekiyor. Sınıfınız dolaylı olarak a'dan oluşturulabildiğinden, MyStruct2
bağımsız / üye olmayan bir bool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
işlev ...
my_MyStruct2 == my_MyStruct1
... önce geçici bir MyStruct1
kaynak oluşturup my_myStruct2
sonra karşılaştırma yaparak. Bu, kesinlikle kurucunun MyStruct1::an_int
varsayılan parametre değerine set bırakacaktır -1
. Eğer içerip içermediğine bağlı olarak an_int
sizin uygulanmasında karşılaştırma operator==
, bir MyStruct1
kudretini veya eşit karşılaştırmak olmayabilir MyStruct2
kendisi eşit karşılaştırır MyStruct1
'ın my_struct_2
üyesi! Dahası, bir geçici oluşturmak MyStruct1
çok verimsiz bir işlem olabilir, çünkü mevcut my_struct2
üyeyi geçiciye kopyalamayı içerir , sadece karşılaştırmadan sonra onu atmak için. (Elbette, bu yapıcıyı MyStruct1
yaparak explicit
veya için varsayılan değeri kaldırarak karşılaştırma için bu örtük yapılandırmayı engelleyebilirsiniz an_int
.)
Üye uygulaması
A ' MyStruct1
dan a' nın örtük olarak oluşturulmasından kaçınmak istiyorsanız MyStruct2
, karşılaştırma işlecini bir üye işlevi yapın:
struct MyStruct1
{
...
bool operator==(const MyStruct1& rhs) const
{
return tie() == rhs.tie();
}
};
Not const
tek üyesi uygulanması için gerekli - - anahtar kelime nesneleri karşılaştırarak bunları değiştirmek olmadığını derleyici bildirir, böylece izin verilebilir const
nesneler.
Görünür temsillerin karşılaştırılması
Bazen istediğiniz türden bir karşılaştırma yapmanın en kolay yolu ...
return lhs.to_string() == rhs.to_string();
... ki bu da genellikle çok pahalıdır - bunlar string
acı bir şekilde atılmak için yaratılmıştır! Kayan nokta değerleri olan türler için, görünür temsillerin karşılaştırılması, görüntülenen basamak sayısının, karşılaştırma sırasında neredeyse eşit değerlerin eşit olarak değerlendirildiği toleransı belirlediği anlamına gelir.
struct
eşitlik için s'nizi nasıl karşılaştırmak istediğinizi bilsin ? Ve basit yolu istiyorsanız,memcmp
yapılarınız her zaman çok uzun süre işaretçi içermiyor.