Funkcja zwracająca wyniki różnych typów(krotka).

0

Mam do was pytanie. Nie chce gotowego kodu chce tylko odpowiedzi czy to jest możliwe do zrobienia i jaki jest tego sens. Znalazłem takie zadanie na cpp0x
(Mam nadzieję że link mogę wrzucić? http://cpp0x.pl/kursy/Kurs-C++/Poziom-3/Wczytywanie-tekstu-standardowy-strumien-wejscia/351)

Treść daję poniżej link dałem dla tych którzy chcą sprawdzić:

Napisz prosty program, który wczyta imię, nazwisko i wiek dwóch osób. Funkcja główna programu ma mieć następującą postać:

int main()
{
    std::string imie[ 2 ];
    std::string nazwisko[ 2 ];
    int wiek[ 2 ];
    for( int i = 0; i < 2; i++ )
         wczytajOsobe( imie[ i ], nazwisko[ i ], wiek[ i ] );
    
    for( int i = 0; i < 2; i++ )
         wypiszOsobe( imie[ i ], nazwisko[ i ], wiek[ i ] );
    
    return 0;
}

I teraz tak na funkcji tego nie zrobie no bo funkcja nie może zwracać dwóch różnych typów danych z tego co wiem więc poszukałem i znalazłem informację o krotkach tworząc coś takiego.

#include <iostream>
#include <tuple>

using namespace std;


tuple <string, string, int> wczytaj()
{
    string im;
    string naz;
    int wi;
    cin>>im>>naz>>wi;
    return tuple<string, string, int>(im,naz,wi);
}
void wypisz(string im, string naz, int wi)
{
    cout<<im<<endl;
    cout<<naz<<endl;
    cout<<wi<<endl;
}

auto dane=wczytaj();

int main()
{
    string imie[2];
    string nazwisko[2];
    int wiek[2];
    for(int i=0; i<2; i++)
    {
        dane=wczytaj();
        imie[i]=get<0>(dane);
        nazwisko[i]=get<1>(dane);
        wiek[i]=get<2>(dane);
    }
    for(int i=0; i<2; i++)
    {
        wypisz(imie[i],nazwisko[i],wiek[i]);
    }
    return 0;
}

Oczywiście działą błędnie (Jeżeli mogę prosić to prosiłbym o pomoc dlaczego bo nie mam pojęcia... Wywołuje mi wczytaj() 3 razy tylko nie wiem dlaczego...)

1

W 21 linii inicjalizujesz zmienną auto przy czym wywołujesz funkcję wczytaj(), a później wiadomo - dwie iteracje, dwa wywołania, czyli w sumie trzy razy wołasz funkcję.

1

Skoro w main masz mieć wczytajOsobe( imie[ i ], nazwisko[ i ], wiek[ i ] ); to chodzi raczej o przesyłanie referencji.
Czyli sygnatura powinna wyglądać

void wczytajOsobe(string& imie, string& nazwisko, int& wiek)

To jest brzydkie, ale skoro tak ma wyglądać wywołanie to cóż poradzić.

0

@tajny_agent:

Ok zrobiłem to na referencjach ale dlaczego uważasz że na referencjach jest brzydko? Czy to co zrobiłem wcześniej na krotce jest lepsze? Czy raczej gorsze? Bo wygląda na bardziej skomplikowane i gorzej zoptymalizowane.

Edit. Ok powyższe było durne... Rozumiem że referencje "nadpisują" wartość im przekazywaną dlatego są one niezbyt ciekawe (Jeżeli nadpiszesz coś czego nie miałeś i to zostanie przekazane dalej może być nieciekawie) a za pomocą krotki niczego nie mogę nadpisać. Dobrze rozumiem czy źle?

void wczytajOsobe(string& imie, string& nazwisko, int& wiek)
{
    cin>>imie;
    cin>>nazwisko;
    cin>>wiek;
}

void wypiszOsobe(string im, string naz, int wi)
{
    cout<<im<<endl;
    cout<<naz<<endl;
    cout<<wi<<endl;
}

int main()
{
    std::string imie[ 2 ];
    std::string nazwisko[ 2 ];
    int wiek[ 2 ];
    for( int i = 0; i < 2; i++ )
         wczytajOsobe( imie[ i ], nazwisko[ i ], wiek[ i ] );

    for( int i = 0; i < 2; i++ )
         wypiszOsobe( imie[ i ], nazwisko[ i ], wiek[ i ] );

    return 0;
}
1

Mniej czytelnie. Nie wiadomo skąd dane są pobierane ani skąd te zmienne się biorą. Dodatkowo jeśli w przyszłości chciałbyś też wczytywać np. płeć to musiałbyś zmieniać sygnaturę funkcji i co za tym idzie każde wywołanie tej funkcji w kodzie.

Oczywiście są wyjątki gdzie przesyłanie przez non-const reference jest ok, ale po coś w końcu ten return jest ;)

1

nie cierpię krotek. To jest zwykle przejaw lenistwa programisty.
Zamiast zdefiniować typ strukturalny ludzie definiują krotki i trzeba pamiętać co jest pod każdą pozycją, albo notorycznie skakać do kodu funkcji, by zobaczyć co właściwie zawiera ta krotka.

W podanym przypadku to już zupełnie pasuje ona jak pięść do oka. Nie prościej zdefiniować typ Osoba i na nim operować, zamiast szpanować "znam krotki" (to jest jedyne uzasadnienie użycia ich w tym wypadku).

Co do linka: http://cpp0x.pl/kursy/Kurs-C++/Poziom-3/Wczytywanie-tekstu-standardowy-strumien-wejscia/351 (popraw go w pytaniu bo jest nieklikalny) to patrząc na jego zawartość, to nie miałbym zaufania do autora tego artykułu. Ot kolejny newbie, który coś liznął trochę wiedzy i próbuje zawojować świat.

0

Od wersji C++17 użycie krotek nie jest już tak nieprzyjemne w użyciu.
W powyższym przypadku wystarczy dodać następujący kod:

std::tuple<string, string, int> wczytaj()
{
  ...
  return std::make_tuple(im,naz,wi);
}
...
auto [ imie, nazwisko, wiek ] = wczytaj();
0

@MarekR22:
Chodziło ci o coś takiego? Jeżeli nie o to to wyjaśnij bo znam jeszcze tylko to... Także tego nauczyłem się na tym forum.

struct Osoba
{
    string imie;
    string nazwisko;
    int wiek;
};

vector <Osoba> dane;

int main()
{
    for(int i=0; i< 2; i++)
    {
        Osoba w;
        cin>>w.imie>>w.nazwisko;
        while(!(cin>>w.wiek))
        {
            cout<<"Pojda liczbe a nie litery..."<<endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
        dane.push_back(w);
    }

    for(int i=0; i<2; i++)
    {
        cout<<dane[i].imie<<"  "<<dane[i].nazwisko<<"  "<<dane[i].wiek<<endl;
    }
    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1