Co tu się dzieje?
if(int a = Func1())
{
// Works.
}
if((int a = Func1()))
{
// Fails to compile.
}
if((int a = Func1())
&& (int b = Func2()))
)
{
// Do stuff with a and b.
// This is what I'd really like to be able to do.
}
Sekcja 6.4.3 standardu z 2003 r. Wyjaśnia, w jaki sposób zmienne zadeklarowane w warunku instrukcji wyboru mają zakres, który rozciąga się do końca podstacji kontrolowanych przez warunek. Ale nie widzę, gdzie mówi cokolwiek o braku możliwości umieszczenia nawiasów wokół deklaracji, ani nie mówi nic o tylko jednej deklaracji na warunek.
To ograniczenie jest irytujące nawet w przypadkach, gdy wymagane jest tylko jedno oświadczenie w warunku. Rozważ to.
bool a = false, b = true;
if(bool x = a || b)
{
}
Jeśli chcę wprowadzić zakres „if” -body z x ustawionym na false, wtedy deklaracja wymaga nawiasu (ponieważ operator przypisania ma niższy priorytet niż logiczne OR), ale ponieważ nie można użyć nawiasu, wymaga deklaracji x na zewnątrz ciała, przeciekając tę deklarację do większego zakresu niż jest to pożądane. Oczywiście ten przykład jest trywialny, ale bardziej realistycznym przypadkiem byłby ten, w którym a i b są funkcjami zwracającymi wartości, które muszą zostać przetestowane
Czy to, co chcę zrobić, jest niezgodne ze standardem, czy też mój kompilator po prostu niszczy mi jaja (VS2008)?
źródło
if
.if
nie jest pętlą, jest warunkiem.while
są takie same jak dlaif
.if (int a = foo(), int b = bar(), a && b)
:? Jeśli operator przecinka nie jest przeciążony, standard mówi, że wyrażenia są obliczane od lewej do prawej, a wartość wyniku jest ostatnim wyrażeniem. Działa zfor
inicjalizacją pętli, dlaczego nie tutaj?if
działa, i wydaje się, że jest to błędne założenie.Odpowiedzi:
Od C ++ 17 to, co próbowałeś zrobić, jest wreszcie możliwe :
Zwróć uwagę na użycie
;
zamiast w,
celu oddzielenia deklaracji od stanu faktycznego.źródło
Myślę, że już wspomniałeś o tym problemie. Co kompilator powinien zrobić z tym kodem?
Operator „&&” to logiczne ORAZ zwarcie. Oznacza to, że jeśli pierwsza część
(1==0)
okaże się fałszywa, to drugiej części(bool a = false)
nie należy oceniać, ponieważ już wiadomo, że ostateczna odpowiedź będzie fałszywa. Jeśli(bool a = false)
nie jest oceniany, to co później zrobić z kodem, który używaa
? Czy po prostu nie zainicjowalibyśmy zmiennej i pozostawilibyśmy ją niezdefiniowaną? Czy zainicjowalibyśmy go domyślnie? A co, jeśli typ danych był klasą i miałoby to niepożądane skutki uboczne? A co by było, gdybyś zamiastbool
ciebie użył klasy i nie miała ona domyślnego konstruktora takiego, że użytkownik musi podać parametry - co wtedy robimy?Oto kolejny przykład:
Wydaje się, że ograniczenie, które znalazłeś, wydaje się całkowicie uzasadnione - zapobiega występowaniu tego rodzaju niejasności.
źródło
Warunek w instrukcji
if
lubwhile
może być wyrażeniem lub deklaracją pojedynczej zmiennej (z inicjalizacją).Twój drugi i trzeci przykład nie są ani prawidłowymi wyrażeniami, ani prawidłowymi deklaracjami, ponieważ deklaracja nie może stanowić części wyrażenia. Chociaż byłoby przydatne móc napisać kod podobny do trzeciego przykładu, wymagałoby to znaczącej zmiany składni języka.
Specyfikacja składni w 6.4 / 1 podaje następujący warunek:
określając jedną deklarację, bez nawiasów ani innych ozdób.
źródło
Jeśli chcesz zawrzeć zmienne w węższym zakresie, zawsze możesz użyć dodatkowych
{ }
źródło
Ostatnia sekcja już działa, wystarczy napisać ją nieco inaczej:
źródło
Oto brzydkie obejście za pomocą pętli (jeśli obie zmienne są liczbami całkowitymi):
Ale to zmyli innych programistów i jest to raczej zły kod, więc nie jest zalecany.
Prosty
{}
blok zamykający (jak już zalecamy) jest znacznie łatwiejszy do odczytania:źródło
Należy również zauważyć, że wyrażenia wewnątrz większego bloku if
niekoniecznie muszą być oceniane w sposób od lewej do prawej. Jeden dość subtelny błąd, który miałem kiedyś, był związany z faktem, że kompilator faktycznie testował od prawej do lewej zamiast od lewej do prawej.
źródło
if(p && p->str && *p->str) ...
. Od prawej do lewej byłoby zabójcze i nie subtelne. Z innymi operatorami - nawet przydział! - i argumenty wywołań funkcji masz rację, ale nie z operatorami zwarć.Dzięki odrobinie magii szablonów można w pewnym sensie obejść problem braku możliwości zadeklarowania wielu zmiennych:
(Uwaga, powoduje to utratę oceny zwarcia).
źródło