Neden c ++ boole'lar için && = veya || = içermiyor?


126

Bir var mı "çok kötü bir şey" olabilir &&=ve ||=için sözdizimsel şeker olarak kullanıldı bool foo = foo && barve bool foo = foo || bar?


5
Şu diğer soruya bakın: stackoverflow.com/questions/2324549/… Bu Java ile ilgili, ancak C soyunu paylaşırken çoğunlukla aynı argümanlar geçerlidir.
jamesdlin

Temel olarak, sadece c ++ 'a sahip değildir, çünkü onlar koymamışlardır - Ruby gibi dillerde vardır. boo ...
Kache

2
Ancak Ruby'de, herhangi bir tür için x ||= ykabaca C ++ ile eşdeğer değil x = x ? x : y;mi? Başka bir deyişle, "önceden ayarlanmadıysa y olarak ayarlayın". Bu, C veya C ++ 'dan önemli ölçüde daha kullanışlıdır x ||= y, ki bu (operatörün aşırı yüklenmesi engellenir) " (bool)yzaten ayarlanmadıysa x olarak ayarlanır". Bunun için başka bir operatör eklemek için endişeli değilim, biraz zayıf görünüyor. Sadece yazın if (!x) x = (bool)y. Ama o zaman, booldeğişkenleri gerçekten sadece bu türle gerçekten yararlı olan ekstra operatörler istemek için yeterince kullanmıyorum .
Steve Jessop

1
Eminim C ++ 'ın birincil nedeni yoktur &&=veya ||=basitçe C'nin bunlara sahip olmamasıdır. C'nin bunlara sahip olmamasının nedeninin, işlevselliğin yeterince yararlı olmadığından eminim.
Jonathan Leffler

2
Ayrıca, aşırı bilgiçlik taslayan gösterim bool foo = foo || bar;, tanımlanmamış davranışa neden olur çünkü foodeğerlendirilmeden önce başlatılmaz foo || bar. Tabii ki, bunun benzer bir şey olması amaçlanmıştır bool foo = …initialization…; …; foo = foo || bar;ve o zaman soru geçerli kalır .
Jonathan Leffler

Yanıtlar:


73

A boolyalnızca trueveya falseC ++ içinde olabilir . Bu nedenle, kullanmak &=ve |=nispeten güvenlidir (gösterimi özellikle sevmeme rağmen). Doğru, mantıksal işlemler yerine bit işlemleri gerçekleştirecekler (ve bu nedenle kısa devre yapmayacaklar), ancak bu bit işlemleri, her iki işlenen de türde olduğu sürecebool mantıksal işlemlere etkin bir şekilde eşdeğer olan iyi tanımlanmış bir eşlemeyi takip edecek . 1

Başkalarının burada söylediklerinin aksine bool, C ++ 'da a asla farklı bir değere sahip olmamalıdır 2. Bu değeri a'ya atarken , standarda boolgöre dönüştürülecektir true.

A'ya geçersiz bir değer almanın tek yolu işaretçiler boolkullanmaktır reinterpret_cast:

int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)

Ancak bu kod yine de tanımlanmamış davranışla sonuçlandığından, C ++ koduna uyum sağlama konusundaki bu potansiyel sorunu güvenle göz ardı edebiliriz.


1 Angew'in yorumunun da gösterdiği gibi, kuşkusuz bu oldukça büyük bir uyarıdır:

bool b = true;
b &= 2; // yields `false`.

Bunun nedeni, b & 2ifadenin daha sonra eşdeğer olacağı şekilde tamsayı yükseltmesi gerçekleştirmesidir static_cast<int>(b) & 2, bu da sonuçlanır ve 0daha sonra tekrar a'ya dönüştürülür bool. Dolayısıyla, bir operator &&=türünün varlığının tip güvenliğini artıracağı doğrudur .


4
Ama && ve || operatörler sadece bool'a değil, bool'a dönüşen her şey üzerinde çalışacaktır .
dan04

13
Boollerde bile aynı şeyi yapmazlar. ||ve &&kısa yol, ikinci bağımsız işlenen ilk işlenen ise değildir, yani true(sırasıyla. falseiçin &&). |, &, |=Ve &=her zaman her iki işleci.
Niki

4
bu && = ve || = neden c ++ operatörü olmadığı sorusuna cevap vermez.
thang

9
Yazının sol tarafı için kullanmak güvenli değildir , çünkü sağ tarafın ( gerçek değer için sıfırdan farklı bir değer döndüren başka bir C stdlib işlevi gibi) dışında bir tür olması tamamen mümkündür . Varsayıma sahip olsaydık, muhtemelen sağ tarafı dönüşmeye zorlar , ki bu olmaz. Başka bir deyişle, sonuçlanır . &=boolboolislower&&=bool&=bool b = true; b &= 2;b == false
Angew artık SO

2
@Antonio Zor kalabalık. 😝
Konrad Rudolph

44

&&ve &farklı anlambilimlere sahiptir: &&birinci işlenen ise ikinci işleneni değerlendirmez false. yani bir şey

flag = (ptr != NULL) && (ptr->member > 3);

güvenli, ama

flag = (ptr != NULL) & (ptr->member > 3);

değil, ancak her iki işlenen de türden bool.

Aynısı &=ve için de geçerlidir |=:

flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();

şunlardan farklı davranacak:

flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();

35
bence && = olması için daha fazla neden. = P
Kache

4
Bu gerçekten bir cevap değil.
Catskul

27

Kısa cevap

Tüm operatörler +=, -=, *=, /=, &=, |=... aritmetik ve aynı beklenti sağlar:

x &= foo()  // We expect foo() be called whatever the value of x

Bununla birlikte, operatörler &&=ve ||=mantıklı olacaktır ve bu operatörler hataya açık olabilir çünkü birçok geliştirici foo()her zaman çağrılmayı bekler x &&= foo().

bool x;
// ...
x &&= foo();           // Many developers might be confused
x = x && foo();        // Still confusing but correct
x = x ? foo() : x;     // Understandable
x = x ? foo() : false; // Understandable
if (x) x = foo();      // Obvious
  • Kısayol almak için C / C ++ 'yı gerçekten daha karmaşık hale getirmemiz gerekiyor x = x && foo()mu?

  • Gerçekten şifreli ifadeyi daha fazla gizlemek istiyor muyuz x = x && foo()?
    Yoksa anlamlı bir kod yazmak if (x) x = foo();mı istiyoruz ?


Uzun cevap

Örnek &&=

Eğer &&=operatör sunulmuştu, sonra bu kodu:

bool ok = true; //becomes false when at least a function returns false
ok &&= f1();
ok &&= f2(); //we may expect f2() is called whatever the f1() returned value

eşdeğerdir:

bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true

Bu ilk kod hataya açıktır çünkü birçok geliştirici f2(), f1()döndürülen değer ne olursa olsun her zaman çağrıldığını düşünür . Sadece döndüğünde aranan bool ok = f1() && f2();yere yazmak gibidir .f2()f1()true

  • Geliştirici aslında f2()yalnızca f1()döndüğünde çağrılmak istiyorsa true, bu nedenle yukarıdaki ikinci kod daha az hataya açıktır.
  • Else (geliştirici f2()her zaman çağrılmak ister) &=yeterlidir:

Örnek &=

bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value

Dahası, derleyicinin yukarıdaki kodu optimize etmesi, aşağıdaki koddan daha kolaydır:

bool ok = true;
if (!f1())  ok = false;
if (!f2())  ok = false;  //f2() always called

Karşılaştır &&ve&

Biz operatörler olmadığını merak edebilir &&ve &üzerinde uygulandığında aynı sonucu verir booldeğerler?

Aşağıdaki C ++ kodunu kullanarak kontrol edelim:

#include <iostream>

void test (int testnumber, bool a, bool b)
{
   std::cout << testnumber <<") a="<< a <<" and b="<< b <<"\n"
                "a && b = "<< (a && b)  <<"\n"
                "a &  b = "<< (a &  b)  <<"\n"
                "======================"  "\n";
}

int main ()
{
    test (1, true,  true);
    test (2, true,  false);
    test (3, false, false);
    test (4, false, true);
}

Çıktı:

1) a=1 and b=1
a && b = 1
a &  b = 1
======================
2) a=1 and b=0
a && b = 0
a &  b = 0
======================
3) a=0 and b=0
a && b = 0
a &  b = 0
======================
4) a=0 and b=1
a && b = 0
a &  b = 0
======================

Sonuç

Bu nedenle EVET biz yerini alabilir &&tarafından &için booldeğerler ;-)
Yani daha iyi kullanmak &=yerine &&=. Booleanlar için yararsız olarak
kabul edebiliriz &&=.

Aynısı ||=

operatör |=aynı zamanda hataya daha az meyillidir||=

Bir geliştirici , bunun yerine f2()yalnızca f1()döndüğünde çağrılmak istiyorsa false:

bool ok = false;
ok ||= f1();
ok ||= f2(); //f2() is called only when f1() returns false
ok ||= f3(); //f3() is called only when f1() or f2() return false
ok ||= f4(); //f4() is called only when ...

Aşağıdaki daha anlaşılır alternatifi tavsiye ederim:

bool ok = false;
if (!ok) ok = f1();
if (!ok) ok = f2();
if (!ok) ok = f3();
if (!ok) ok = f4();
// no comment required here (code is enough understandable)

veya hepsini tek çizgi stilinde tercih ederseniz :

// this comment is required to explain to developers that 
// f2() is called only when f1() returns false, and so on...
bool ok = f1() || f2() || f3() || f4();

13
Ya gerçekten bu davranışı istiyorsam? Sol eldeki ifade yanlışsa sağ el ifadesinin çalıştırılmaması. Değişkenleri iki kez yazmak can sıkıcı, örneğinsuccess = success && DoImportantStuff()
Niklas R

1
Benim tavsiyem yazmak if(success) success = DoImportantStuff(). İfadeye success &&= DoImportantStuff()izin verilseydi, birçok geliştirici DoImportantStuff(), değeri ne olursa olsun her zaman çağrıldığını düşünürdü success. Umarım bu merak ettiğiniz şeyi cevaplar ... Cevabımın birçok bölümünü de geliştirdim. Lütfen şimdi cevabımın daha anlaşılır olup olmadığını söyle. (yorumunuz hakkında) Şerefe, Görüşmek üzere ;-)
olibre

9
"İfadeye success &&= DoImportantStuff()izin verilseydi, birçok geliştirici DoImportantStuff()başarının değeri ne olursa olsun her zaman çağrıldığını düşünürdü ." if (success && DoImportantStuff())Yine de bunu söyleyebilirsin . If sözdiziminin arkasındaki mantığı hatırladıkları sürece sorun yaşamazlar &&=.
pilkch

2
İnsanların f1()her zaman içinde değerlendirildiğini, ok &&= f(1) ancak her zaman içinde değerlendirileceğini varsaymayacağını nasıl varsayabileceklerini anlamıyorum ok = ok && f(1). Bana da öyle geliyor.
einpoklum

1
Aslında v1 değişkeninin ve e2 ifadesinin v1 += e2sözdizimsel şeker eşdeğeri olmasını bekliyorum v1 = v1 + e1. Sadece kısa bir gösterim, hepsi bu.
einpoklum
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.