Czy nawiasy wokół wyniku mają znaczenie w instrukcji zwrotu?


79

Czy istnieje różnica między tymi dwoma instrukcjami wewnątrz funkcji?

bool returnValue = true;
// Code that does something
return(returnValue);

i to?

bool returnValue = true;
// Code
return returnValue;

Pierwsza z nich ma nawiasy wokół returnValue.


Dzięki Rob, udało Ci się uchwycić ducha pytania. W Essence zastanawiałem się, czy kompilator zrobił coś specjalnego (np. Próbował najpierw ocenić wyrażenie), czy po prostu to zignorował.
Jose Villalta

1
Trudno odpowiedzieć na to pytanie dla żadnego c++ / c. Dobrze byłoby bardziej szczegółowo określić definicję języka, ale 9 lat później nie wiem, jak to naprawić.
Jonas Stein

Ponieważ Cistnieje zduplikowany stackoverflow.com/questions/161879/ ...
Jonas Stein

Odpowiedzi:


122

Począwszy od C ++ 14, często tak jest.

C ++ 14 dodaje przypadek fringe, w którym nawiasy wokół zwracanej wartości mogą zmienić semantykę. Ten fragment kodu przedstawia deklarowane dwie funkcje. Jedyną różnicą są nawiasy wokół zwracanej wartości.

int var1 = 42;
decltype(auto) func1() { return var1; } // return type is int, same as decltype(var1)
decltype(auto) func1() { return(var1); } // return type is int&, same as decltype((var1))

W pierwszym func1zwraca an, intaw drugim func1zwraca an int&. Różnica w semantyce jest bezpośrednio związana z otaczającymi nawiasami .

Specyfikator autow swojej najnowszej postaci został wprowadzony w C ++ 11. W specyfikacji języka C ++ jest to opisane jako:

Określa, że ​​typ deklarowanej zmiennej zostanie automatycznie wydedukowany z jej inicjatora. W przypadku funkcji określa, że ​​typ zwracany jest końcowym typem zwracanym lub zostanie wydedukowany z jego instrukcji powrotu (od C ++ 14)

C ++ 11 również wprowadził decltypespecyfikator, który jest opisany w specyfikacji języka C ++ :

Sprawdza zadeklarowany typ jednostki lub pyta o zwracany typ wyrażenia.

[fantastyczna okazja]

  1. Jeśli argumentem jest nieprzedstawiona nazwa obiektu / funkcji lub wyrażenie dostępu do elementu członkowskiego (element_obiektu lub wskaźnik-> element członkowski), to decltype określa zadeklarowany typ jednostki określony przez to wyrażenie.

  2. Jeśli argument jest jakimkolwiek innym wyrażeniem typu T, to

    a) jeśli kategorią wartości wyrażenia jest xvalue, to decltype określa T &&

    b) jeśli kategorią wartości wyrażenia jest lwartość, to decltype określa T &

    c) w przeciwnym razie decltype określa T

[fantastyczna okazja]

Zauważ, że jeśli nazwa obiektu jest umieszczona w nawiasach, staje się ona wyrażeniem l-wartości, dlatego decltype (arg) i decltype ((arg)) są często różnymi typami.

W C ++ 14 można decltype(auto)było używać zwracanych typów funkcji. W oryginalnych przykładach pojawia się różnica semantyczna z nawiasami. Wracając do oryginalnych przykładów:

int var1 = 42;
decltype(auto) func1() { return var1; } // return type is int, same as decltype(var1)
decltype(auto) func1() { return(var1); } // return type is int&, same as decltype((var1))

decltype(auto)umożliwia wywodzenie końcowego typu zwracanego w funkcji z jednostki / wyrażenia w instrukcji return. W pierwszej wersji return var1;jest to w praktyce to samo, co zwracanie typu decltype(var1)( typ intzwracany przez regułę 1 powyżej), aw drugim przypadku return (var1);jest faktycznie to samo, co decltype((var1))( int &typ zwracany przez regułę 2b).

Nawiasy tworzą zwracany typ int&zamiast int, co powoduje zmianę semantyki. Morał z tej historii - „Nie wszystkie nawiasy w zwracanym typie są sobie równe”


Instrukcja return bez nawiasów nadal jest wyrażeniem l-wartości, prawda? Chyba że jest traktowana jako wartość xw tym scenariuszu. Czy możesz wyjaśnić kategorię wartości zwrotu bez nawiasów?
void.pointer

1
Instrukcja return zwraca odczyt wprowadzonego wyrażenia, tj. Przechwytuje wartość r z wyrażenia, które zawiera, i zwraca ją. Nigdy nie zwracamy lwartości. Może się zdarzyć, że jakiś kompilator ma błąd pasujący do podanego tutaj opisu iz powodów, które tu podajesz, ale nigdy nie powinno tak być, że return (x);jest to równoważne return &x;, ani nie powinno być możliwe, aby zwracał wartość x, ale z odniesieniem do typu x.
Theodore Murdock

4
Wow, co za ohydna konstrukcja językowa. Po prostu całkowicie ... nieprzezroczysty. Ale niezła notatka, dziękuję.
Paul Sanders

5
C ++ to niezwykle interesujący język. Ale tego rodzaju ukryte "cechy" czasami doprowadzają mnie do szału ...
andreee,

Nasz kod jest pełen tych zbędnych nawiasów. Używamy też autodość często. Czy nasza semantyka nigdy się nie zmienia, dopóki trzymamy się z daleka decltype? Obawiam się nieoczekiwanego zachowania, gdy przechodzimy do kolejnej wersji kompilatora, która zawiera następny program Visual Studio.
OneWorld

6

Nie ma różnicy.

Jednym z powodów użycia nawiasów byłoby sprawdzenie wyrażenia przed zwróceniem, ale w Twoim przykładzie nie byłoby powodu. Widzieć:

Nawiasy otaczające zwracane wartości

do dalszej dyskusji.


3
Chociaż nawet przy skomplikowanym wyrażeniu, te nawiasy nadal nie powodują innego zachowania. Po prostu sprawiają, że znaczenie jest bardziej oczywiste (subiektywnie!) Dla ludzkich czytelników.
aschepler

@Karl "Jednym z powodów użycia nawiasów jest to, że chciałbyś ocenić wyrażenie przed zwróceniem" Czy możesz podać przykład?
Chris Middleton

3
@ChrisMiddleton Nie, ponieważ twierdzenie jest tutaj równie bezsensowne, jak w tym wątku. Nie ma żadnej funkcjonalnej różnicy między return m * x + ci return (m * x + c)lub return ( (m * x) + c )lub itd. - i nie wygląda to lepiej ani bardziej intuicyjnie, jeśli o mnie chodzi.
underscore_d

5

Nawiasy w górnym przykładzie są zbędne; są skutecznie ignorowane.

To byłoby to samo, co coś takiego ...

int x = (5);

Tutaj również nawiasy są ignorowane.


Cóż, technicznie rzecz biorąc, nie są ignorowane , po prostu nie mają wpływu na wartość wyrażenia.
John Bode,

1
@John: skutecznie ignorowane. :)
James

3
+1… to jedyna odpowiedź, która stwierdza, że ​​nawiasy są w rzeczywistości zbędne i pokazuje, że ich użycie jest trochę głupie.
Konrad Rudolph

4

AFAIK, nic nie jest inne.

W C ++ wyrażenia mogą mieć postać: exprlub (expr). Tak więc to drugie jest wyrażeniem wymagającym więcej pisania. Aby dowiedzieć się więcej na ten temat, zapoznaj się z gramatyką (poszukaj „wyrażenia”).


David, dzięki za link. Mam gramatykę w książce Stroustrupa C ++, ale (chyba z lenistwa) nie zaglądaj do niej tak często, teraz, gdy mam ją w zakładkach w przeglądarce, mogę do niej częściej odwoływać się.
Jose Villalta


3

Zakładam, że booto literówka, a Ty pytasz, czy jest różnica między

return expr;

i

return(expr);

Odpowiedź brzmi nie.


2

Bez różnicy!!

Ludzie używają nawiasów, jeśli w grę wchodzi złożone wyrażenie.

BTW returnto instrukcja, a nie funkcja.


2

Nie, nie ma między nimi różnicy, chociaż możesz dodać nawiasy, jeśli dzięki temu wyrażenie będzie łatwe do odczytania i zrozumiałe.


1
... ale nigdy tak nie jest. Dlaczego miałoby to robić? Co jest trudne do odczytania w przypadku wyrażenia, które nie zostało z rodzicami? Dodanie nawiasów wygląda dla mnie jak bałagan. A jeśli chodzi o pozór jaśniej, czy ludzie myślą, że returnjest chciwym operatorem, który return m * x + cmoże wrócić mi odrzucić resztę, czy co?
underscore_d

1

Znacząco spowalniasz kompilator!

Obecność nawiasów nie tylko spowalnia fazę przetwarzania wstępnego, ale także generuje bardziej skomplikowane drzewo składni abstrakcyjnych: więcej pamięci, więcej obliczeń.


Z semantycznego punktu widzenia? Są dokładnie identyczne. Niezależnie od tego, czy istnieją nawiasy, czy nie, returninstrukcja w pełni oceni wyrażenie przed zwróceniem go.


5
Moje myślenie dokładnie. Sprawiając, że kompilator wykonuje niepotrzebną pracę, analizując bezużyteczny bałagan, zbliża się do śmierci wszechświata bez powodu.
Maxim Egorushkin

4
Co myślisz o bitcoinach?
Jeremy Nikolai

0

Są identyczne. Dość często widzę składnię nawiasów i zawsze pytam tych, którzy jej używają: dlaczego ? I nikt nie może odpowiedzieć, dlaczego go używają.

Podsumowując bez ogródek, nawiasy wokół zwracających wyrażeń są używane przez osoby, które nie do końca rozumieją różnicę między makrami i funkcjami podobnymi do funkcji lub są zdezorientowane co do pierwszeństwa operatorów lub kolejności reguł oceny w C. Nie ma kodowania. style korzystają z używania nawiasów.

A zatem

return value;

jest bardziej poprawne niż

return (value)

bo to drugie sugeruje, że nie bardzo wiesz, co robisz :)


-3

W twoim przypadku oba są takie same.


MM, czy mógłbyś wyjaśnić swój komentarz?
Zeshan Khan

1
Jeśli ajest 5następnie return a++;i return (a++);(które są takie same) wierszową5
MM

2
w szczególności postinc / dekrementacja zwraca wartość przed modyfikacją swojego operandu i żadna ilość nawiasów ani inne bezowocne próby wymuszenia tego nie zmienią.
underscore_d
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.