Jak nazywa się ta funkcjonalność C ++?

82

Pisałem trochę kodu C ++ i omyłkowo pominąłem nazwę funkcji WSASocket. Jednak mój kompilator nie zgłosił błędu i skojarzył my SOCKETz wartością całkowitą 1 zamiast z prawidłowym gniazdem.

Kod, o którym mowa, powinien wyglądać następująco:

this->listener = WSASocket(address->ai_family, address->ai_socktype, address->ai_protocol, NULL, NULL, WSA_FLAG_OVERLAPPED);

Ale zamiast tego wyglądało to tak:

this->listener = (address->ai_family, address->ai_socktype, address->ai_protocol, NULL, NULL, WSA_FLAG_OVERLAPPED);

Pochodzący z innych języków, wygląda na to, że może to być rodzaj anonimowego typu. Jak nazywa się funkcja, w przypadku gdy jest to naprawdę funkcja?

Jaki jest jej cel?

Trudno go znaleźć, kiedy nie wiesz, od czego zacząć.

Michael J. Gray
źródło
3
+1, fajne pytanie do quizu w pubie (lub przerażające pytanie do wywiadu dla firm, które lubią zatrudniać ludzi, którzy są dobrzy w łamigłówkach).
Batszeba
8
Link do artykułu w Wikipedii na temat operatora przecinka . FWIW, jednym z typowych zastosowań jest uzyskanie dwóch efektów ubocznych w forwyrażeniu iteracji pętli * , ala dla (int i = 0, j = 0; i <10; ++ i, --j) ... `
Tony Delroy
1
@ MichaelJ.Gray Technicznie się mylisz. To nie jest nadpisywanie zachowania. Wyobraź sobie: i=0;j=0;x=i++,j=6;x i j będzie równe 6, a i i tak będzie 1. Jeśli zachowanie i ++ zostanie nadpisane, pozostanie 0. Ale każda instrukcja jest wywoływana i po osiągnięciu tego ,samego rozszerzenia są odrzucane i wywoływany jest następny pseudosekwencyjny punkt. Tak więc pierwszy =przypisuje tylko część po ostatnim, ,ale każdy punkt jest wywoływany. W każdym razie: nie rozumiem, dlaczego kompilator nie ostrzega przed przedefiniowaniem deklaracji funkcji i zamiast tego zmienia kod na coś o
innym
5
Jeśli użyjesz odpowiedniego kompilatora z włączonymi ostrzeżeniami, ostrzeże on o takim podejrzanym kodzie, na przykład gcci g++z -Wallopcją powiedz:warning: left-hand operand of comma expression has no effect [-Wunused-value]
Sam Watkins
3
Więc moim zdaniem najlepszą odpowiedzią na to pytanie jest „zawsze włączaj ostrzeżenia” - wtedy kompilator sam wyjaśni, że wystąpił błąd i powie Ci co zrobiłeś; a ta odpowiedź rozwiąże również wiele innych problemów.
Sam Watkins

Odpowiedzi:

151

Operator przecinka † oblicza lewą stronę, odrzuca jej wartość iw rezultacie zwraca prawą stronę. WSA_FLAG_OVERLAPPEDwynosi 1, i to jest wynik wyrażenia; wszystkie inne wartości są odrzucane. Żadne gniazdo nie jest nigdy tworzone.


† Chyba że jest przeciążony. Tak, może być przeciążony. Nie, nie powinieneś go przeciążać. Odsuń się od klawiatury już teraz!

R. Martinho Fernandes
źródło
9
+1, duch wzmocnienia bardzo skutecznie przeciąża operator przecinka, ale jest to bardzo samotny wyjątek od reguły: nie rób tego .
Batszeba
2
@Bathsheba Boost.Assign również przeciąża operator przecinka, ale kto używa tego od C ++ 11?
rubenvb
39
Ale miałeś najlepsze wyjaśnienie, jak straszny może być potężny przecinek. Bezlitosny i pełen wyśmiewania, nękał mój kod przez kilka minut, wpatrując się we mnie bez wstydu za swoje zachowanie.
Michael J. Gray
1
@ R.MartinhoFernandes - Eigen również bardzo skutecznie przeciąża operator przecinka. Zobacz to pytanie SE, aby zobaczyć przykładowe użycie.
David Hammen,
22

Operatora przecinek jest sens swojego kodu.

Skutecznie ustawiasz, this->listener = WSA_FLAG_OVERLAPPED;co akurat jest poprawne syntatycznie.

Batszeba
źródło
3
Nie tylko poprawna składniowo, ale ponieważ interfejs API systemu Windows nie jest bezpieczny pod względem typu, jest to również poprawna konwersja.
MSalters
5
@MSalters nie, że POSIX jest znacznie lepszy pod tym względem
chbaker0
1
Dlatego konstruktory wywoływane za pomocą jednego argumentu powinny być jawne , wtedy wystąpiłby błąd kompilatora, a programista miałby szansę ponownie przyjrzeć się tej dziwacznej konstrukcji.
Matthieu M.
@MSalters Cóż, SOCKETjest typedef dla unsigned inti WSA_FLAG_OVERLAPPEDjest intdosłownym. Gdyby SOCKETbył synonimem int, nie byłoby to nawet konwersją .
Joker_vD,
1
@Joker_vD: Rzeczywiście. Gdyby zrobili to jako typ for struct __socket*, mielibyśmy mniej błędów. Ale jest po prostu zbyt dużo kodu, który „wie” SOCKETjest integralną częścią.
MSalters
21

Kompilator ocenia po kolei każdy punkt sekwencji w nawiasach, a wynikiem jest końcowe wyrażenie,WSA_FLAG_OVERLAPPED w wyrażeniu.

Operator przecinka ,to punkt sekwencji w C ++. Wyrażenie po lewej stronie przecinka jest w pełni oceniane przed wyrażeniem po prawej stronie. Wynik jest zawsze wartością po prawej stronie. Kiedy masz wyrażenie postaci (x1, x2, x3, ..., xn), wynikiem tego wyrażenia jest zawsze xn.

Sean
źródło
Po dodaniu tam wyjaśnienia ma to większy sens. Na początku nie do końca rozumiałem znaczenie kwestii punktu sekwencji.
Michael J. Gray