Zwracanie wielu wartości z funkcji C ++
Czy istnieje preferowany sposób zwracania wielu wartości z funkcji C ++? Na przykład wyobraź sobie funkcję, która dzieli dwie liczby całkowite i zwraca iloraz i resztę. Jednym ze sposobów, który zwykle widzę, jest użycie parametrów referencyjnych:
void divide(int dividend, int divisor, int& quotient, int& remainder);
Odmiana powinna zwracać jedną wartość i przekazywać inną przez parametr odwołania:
int divide(int dividend, int divisor, int& remainder);
Innym sposobem byłoby zadeklarowanie struktury zawierającej wszystkie wyniki i zwrócenie jej:
struct divide_result {
int quotient;
int remainder;
};divide_result divide(int dividend, int divisor);
Czy jedna z tych metod jest ogólnie preferowana, czy też istnieją inne sugestie?
Edycja: w rzeczywistym kodzie mogą występować więcej niż dwa wyniki. Mogą też być różnego rodzaju.
Nie znaleziono powiązanych wyników
Zaproszony:
Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się
20 odpowiedzi
Anonimowy użytkownik
Potwierdzenie od:
Wraz z wprowadzeniem strukturalnego wiązania w C ++ 17, zwracanie powinno prawdopodobnie stać się akceptowanym standardem.
Anonimowy użytkownik
Potwierdzenie od:
W C ++ 17:
lub ze strukturami:
Anonimowy użytkownik
Potwierdzenie od:
Mam również pewne zastrzeżenia dotyczące techniki pary/krotki. W większości przypadków nie ma naturalnego uporządkowania zwracanych wartości. W jaki sposób czytelnik kodu może wiedzieć, czy wynik. Najpierw jest czynnikiem, czy resztą? Wykonawca może zmienić kolejność, która łamie istniejący kod. Jest to szczególnie trudne, jeśli wartości są tego samego typu, więc nie zostanie wygenerowany żaden błąd kompilatora ani ostrzeżenie. W rzeczywistości te argumenty dotyczą również zwracanych parametrów.
Oto kolejny przykład kodu, tym razem trochę mniej trywialny:
Czy to powoduje wydrukowanie prędkości względem ziemi i kursu, czy też kursu i prędkości względem ziemi? To nie jest oczywiste.
Porównaj z tym:
Myślę, że to jest wyraźniejsze niż jasne.
Więc myślę, że moim pierwszym wyborem w ogóle jest technika konstrukcji. W niektórych przypadkach idea pary/krotki jest prawdopodobnie świetnym rozwiązaniem. Chciałbym uniknąć zwracania parametrów, gdy tylko jest to możliwe.
Anonimowy użytkownik
Potwierdzenie od:
std :: pair to zasadniczo rozwiązanie strukturalne, ale już zdefiniowane dla Ciebie i gotowe do dostosowania do dowolnych dwóch typów danych.
Anonimowy użytkownik
Potwierdzenie od:
Anonimowy użytkownik
Potwierdzenie od:
Właściwie myślę, że ktoś zalecił zwrócenie struktury, która jest wystarczająco bliska, ale przesłania intencję, że powinna to być w pełni przemyślana klasa z konstruktorem i wieloma metodami, a właściwie ta „metoda”, o której wspomniałeś pierwotnie (jako zwracająca parę) powinna być najprawdopodobniej element członkowski tej klasy zwracający własną instancję.
Wiem, że twój przykład to po prostu „Przykład”, ale chodzi o to, że jeśli twoja funkcja nie robi dużo więcej niż powinna robić jakakolwiek funkcja, jeśli chcesz, aby zwracała wiele wartości, prawie na pewno brakuje ci obiektu.
Nie krępuj się tworzyć tych małych klas, aby wykonywać małe fragmenty pracy - to magia OO - kończysz ją na części, aż każda metoda będzie bardzo mała i prosta, a każda klasa będzie mała i prosta.
Jeszcze jedna rzecz, która powinna wskazywać, że coś było nie tak: w OO praktycznie nie masz danych - w OO nie chodzi o transfer danych, klasa musi wewnętrznie zarządzać własnymi danymi i manipulować nimi, każdy transfer danych (w tym dostęp do metod) jest znak, że być może trzeba będzie coś przemyśleć.
Anonimowy użytkownik
Potwierdzenie od:
W C ++ 17 możesz również zwrócić jedną lub więcej ustalonych/niepodlegających kopiowaniu wartości
(w niektórych przypadkach). Możliwość zwracania stałych typów pochodzi z nowych optymalizacji gwarantowanych zwrotów i dobrze się z nimi łączy
kruszywa
i co można nazwać
konstruktorzy szablonów
.
Najlepsze w tym jest to, że na pewno nie spowoduje
Nie
skopiuj lub przenieś. Możesz również zrobić przykład wariadyczny o strukturach. Nowe szczegóły:
Zwracanie agregatów ze zmienną liczbą argumentów (strukturą) i składnią dla szablonu zmiennej C ++ 17 `` Przewodnik po odliczaniu konstrukcji ''
https://coderoad.ru/38393302/
Anonimowy użytkownik
Potwierdzenie od:
„Mieszanka wartości zwracanej i parametrów zwracanych” jest zwykle najmniej czysta.
Posiadanie funkcji, która zwraca stan i zwraca dane poprzez parametry zwracane, ma sens w C; jest to mniej sensowne w C ++, gdzie zamiast tego można użyć wyjątków do przekazywania informacji o awarii.
Jeśli istnieje więcej niż dwie wartości zwracane, prawdopodobnie najlepiej jest użyć mechanizmu podobnego do struktury.
Anonimowy użytkownik
Potwierdzenie od:
Zwrócenie struktury z samodokumentującymi się nazwami zmiennych składowych prawdopodobnie będzie mniej podatne na błędy dla osób używających Twojej funkcji. Zakładając na chwilę kapelusz kolegi, struktura jest dla mnie, potencjalnego użytkownika Twojej funkcji, łatwa do zrozumienia w ciągu 2 sekund. Majstrowanie przy parametrach wyjściowych lub tajemniczych parach i krotkach zajmie więcej czasu do odczytania i może być niewłaściwie użyte. I najprawdopodobniej nawet po kilkukrotnym użyciu funkcji nadal nie pamiętam prawidłowej kolejności argumentów.
Anonimowy użytkownik
Potwierdzenie od:
Jeśli skorzystasz z linku, ucierpi na tym optymalizacja programu
Anonimowy użytkownik
Potwierdzenie od:
W ten sposób możesz jasno zrozumieć, że w ten sposób możesz zwrócić wiele wartości z funkcji. podczas używania std :: pair można zwrócić tylko 2 wartości, a std :: tuple może zwrócić więcej niż dwie wartości.
Anonimowy użytkownik
Potwierdzenie od:
Użyj parametrów odniesienia:
użyj parametrów wskaźnika:
co ma tę zaletę, że musisz na stronie wywołania, być może ostrzegając ludzi, że jest to parametr out.
Napisz szablon i użyj go:
wtedy możemy to zrobić:
i to wszystko dobrze. nie może już czytać żadnej wartości przekazanej jako bonus.
Do wykreślenia można użyć innych sposobów zdefiniowania punktu, w którym można umieścić dane. Na przykład oddzwonienie do umieszczenia gdzieś rzeczy.
Możemy zwrócić konstrukcję:
whick działa dobrze w każdej wersji C ++ oraz w
c++17
https://coderoad.ru/?tag=c%2b%2b17
umożliwia również:
auto&&[result, other_result]=foo();
bez kosztów. Parametry nie mogą być nawet zmieniane dzięki gwarantowanej elizji.
Moglibyśmy zwrócić :
co ma tę wadę, że parametry nie są nazywane. Pozwala to na użycie
c++17
https://coderoad.ru/?tag=c%2b%2b17
:
auto&&[result, other_result]=foo();
również. Przed
c++17
https://coderoad.ru/?tag=c%2b%2b17
zamiast tego możemy zrobić:
co jest jeszcze bardziej krępujące. Jednak gwarantowana Elicia nie działa tutaj.
Gdy wjedziemy na obce terytorium (a to po !), Możemy skorzystać z kontynuacji przechodząc przez styl:
a teraz dzwoniący robią to:
Zaletą tego stylu jest to, że możesz zwrócić dowolną liczbę wartości (z jednolitym typem) bez konieczności zarządzania pamięcią:
wywołanie zwrotne można wywołać 500 razy, gdy
get_all_values ([& amp;] (int value) {})
.W przypadku czystego szaleństwa możesz nawet użyć kontynuacji w sequelu.
którego korzyść wygląda następująco:
co spowodowałoby ustanowienie relacji wiele-jeden między a .
Ponownie, jako wartość dla Ciebie, możemy to zrobić:
tutaj wywołujemy oddzwonienie z szeregiem wyników. Możemy to robić nawet wielokrotnie.
Używając tego, możesz mieć funkcję, która wydajnie przesyła megabajty danych bez dokonywania alokacji ze stosu.
Teraz jest do tego trochę ciężkie, ponieważ będziemy to robić w środowiskach o zerowym narzutu bez przydzielania zasobów. Dlatego chcielibyśmy mieć https://foonathan.net/blog/201 ... .html
który nigdy się nie wyróżnia.
Jest inne rozwiązanie:
gdzie zamiast pobierać callback i wywoływać go, zamiast tego zwraca funkcję, która akceptuje callback.
foo (7) ([& amp;] (int wynik, int inny_wynik) {/ * kod */});
umożliwia to oddzielenie parametrów wyjściowych od parametrów wejściowych oddzielnymi nawiasami.
Z coroutines i
c++20
https://coderoad.ru/?tag=c%2b%2b20
możesz sprawić, że będzie generatorem typu zwracanego wariantu (lub po prostu typu zwracanego). Składnia nie została jeszcze poprawiona, więc nie podam przykładów.
W świecie sygnałów i slotów funkcja zapewniająca zestaw sygnałów:
pozwala stworzyć , który działa asynchronicznie i przekazuje wynik po zakończeniu.
W tej linii mamy wiele potokowych metod, w których funkcja nie robi czegoś, ale raczej organizuje dane, które muszą być w jakiś sposób połączone, i jest to stosunkowo niezależna akcja.
to ten kod to nic
robi
dopóki nie będzie zawierał liczb całkowitych, aby to podać. W takim przypadku wyniki zaczną uzyskiwać wyniki i .
Anonimowy użytkownik
Potwierdzenie od:
Anonimowy użytkownik
Potwierdzenie od:
generatory
http://en.wikipedia.org/wiki/Generator_(computer_science)
i
odwrócenie sterowania
http://en.wikipedia.org/wiki/Inversion_of_Control
ale żaden z nich nie pasuje tutaj.
Niektóre (jak Microsoft w historycznym Win32) mają tendencję do używania parametrów referencyjnych dla uproszczenia, ponieważ jest jasne, kto przydziela i jak będzie wyglądać na stosie, zmniejsza mnożenie się struktur i umożliwia oddzielną wartość zwracaną dla sukcesu.
Programiści „czystej” preferują strukturę, zakładając, że tak jest
wartość funkcji (jak w tym przypadku), a nie to, na co funkcja wpływa przypadkowo. Gdybyś miał bardziej złożoną procedurę lub coś ze stanem, prawdopodobnie użyłbyś referencji (zakładając, że masz powód, aby nie używać tej klasy).
Anonimowy użytkownik
Potwierdzenie od:
Często wolę przekazywać „struktury” przez odniesienie na liście parametrów, zamiast mieć narzut kopiowania przy zwracaniu nowej struktury (ale to się przejmuje drobiazgami).
Czy nasze parametry są mylące? Parametr wysłany jako odwołanie zakłada, że wartość ulegnie zmianie (w przeciwieństwie do odwołania do stałej). Rozsądne nazewnictwo usuwa również zamieszanie.
Anonimowy użytkownik
Potwierdzenie od:
Aby odpowiedzieć na Twoje pierwotne pytanie, w tym przykładzie zastosowano metodę, która zwraca czynnik, którego może potrzebować większość wywołujących, a ponadto po wywołaniu metody można pobrać pozostałą część jako element danych.
Anonimowy użytkownik
Potwierdzenie od:
Anonimowy użytkownik
Potwierdzenie od:
Możliwy przykład:
Anonimowy użytkownik
Potwierdzenie od:
Anonimowy użytkownik
Potwierdzenie od:
użyj „static”, aby ograniczyć zakres zwracanego typu do tej jednostki kompilacji, jeśli dotyczy on tylko tymczasowego zwracanego typu.
To zdecydowanie nie jest najmilszy sposób na zrobienie tego, ale zadziała.