Eşitlik operatörü, C ++ 20'de özel bir uzay gemisi operatörü uygulaması için tanımlanmıyor


51

<=>C ++ 20 yeni uzay gemisi operatörü ile garip bir davranış içine koşuyorum . Visual Studio 2019 derleyicisini ile kullanıyorum /std:c++latest.

Bu kod beklendiği gibi iyi derlenir:

#include <compare>

struct X
{
    int Dummy = 0;
    auto operator<=>(const X&) const = default; // Default implementation
};

int main()
{
    X a, b;

    a == b; // OK!

    return 0;
}

Ancak, X'i bu şekilde değiştirirsem :

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
};

Aşağıdaki derleyici hatasını alıyorum:

error C2676: binary '==': 'X' does not define this operator or a conversion to a type acceptable to the predefined operator

Bunu clang'da da denedim ve benzer davranışlar elde ediyorum.

Varsayılan uygulamanın neden operator==doğru bir şekilde oluşturduğuna dair bazı açıklamaları takdir ediyorum , ancak özel olan bunu yapmıyor.

Yanıtlar:


50

Bu tasarım gereğidir.

[class.compare.default] (benimkini vurgulayın)

3 Sınıf tanımı, bir == işleç işlevini açıkça bildirmezse , ancak varsayılan üç yönlü karşılaştırma işleç işlevi bildirirse, işleç işlevi, üç yönlü karşılaştırma işleç işleviyle ==aynı erişimle örtülü olarak bildirilir. ==X sınıfı için dolaylı olarak bildirilen işleç, satır içi bir üyedir ve X tanımında varsayılan olarak tanımlanmıştır.

Sadece temerrüde düşmüş <=>bir sentezin var ==olmasına izin verir . Bunun mantığı şudur: like sınıfları std::vectortemerrüde düşmüşleri kullanamazlar <=>. Buna ek olarak, kullanarak <=>için ==vektörler karşılaştırmak için en etkili yol değildir. <=>kesin sipariş vermelidir, oysa ==önce boyutları karşılaştırarak erken kefalet verebilir.

Bir sınıf üç yönlü karşılaştırmasında özel bir şey yaparsa, büyük olasılıkla özel bir şey yapması gerekecektir ==. Böylece, mantıksız bir varsayılan oluşturmak yerine, dil onu programcıya bırakır.


4
Uzay gemisi arabası olmadığı sürece kesinlikle mantıklı. Gerçi potansiyel olarak oldukça verimsiz ...
Deduplicator

1
@Deduplicator - Hassasiyet özneldir. Bazıları sessizce üretilen verimsiz bir uygulamanın mantıklı olmadığını söyler.
StoryTeller - Unslander Monica

45

Bu özelliğin standardizasyonu sırasında, eşitlik ve düzenin mantıksal olarak ayrılması gerektiğine karar verildi. Bu nedenle, eşitlik testinin ( ==ve !=) kullanımı asla çağrılmaz operator<=>. Bununla birlikte, her ikisini de tek bir bildirimle varsayılan hale getirebilmek hala yararlı görünüyordu. Bu nedenle, varsayılan operator<=>olarak ayarlamanız gerektiğine karar verildi operator==(daha sonra tanımlamadığınız veya daha önce tanımlamadığınız sürece).

Bu kararın neden alındığına gelince , temel akıl yürütme böyle gider. Düşünün std::string. İki dizenin sıralanması sözlükbilimseldir; her karakterin diğer dizgideki her karakterle karşılaştırıldığında tamsayı değeri vardır. İlk eşitsizlik, siparişin sonucudur.

Ancak, dizelerin eşitlik testinde kısa devre vardır. İki dize eşit uzunlukta değilse, karakter açısından karşılaştırma yapmanın bir anlamı yoktur; eşit değiller. Birisi eşitlik testi yapıyorsa, kısa devre yapabiliyorsanız uzun formda yapmak istemezsiniz.

Kullanıcı tanımlı bir sıralamaya ihtiyaç duyan birçok türün eşitlik testi için bazı kısa devre mekanizması sunacağı ortaya çıkıyor. İnsanların yalnızca uygulamalarını operator<=>ve potansiyel performansı atmalarını önlemek için herkesi etkili bir şekilde her ikisini de yapmaya zorlarız.


5
Bu kabul cevap çok daha iyi bir açıklaması var
memo

17

Diğer cevaplar, dilin neden böyle olduğunu çok iyi açıklıyor. Sadece açık değilse, operator<=>varsayılan olarak bir kullanıcı tarafından sağlanabileceğini eklemek istedim operator==. Sadece varsayılan olarak açıkça yazmanız gerekir operator==:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.