Restituzione di più valori da una funzione C ++


242

Esiste un modo preferito per restituire più valori da una funzione C ++? Ad esempio, immagina una funzione che divide due numeri interi e restituisce sia il quoziente che il resto. Un modo in cui vedo comunemente è usare i parametri di riferimento:

void divide(int dividend, int divisor, int& quotient, int& remainder);

Una variazione consiste nel restituire un valore e passare l'altro attraverso un parametro di riferimento:

int divide(int dividend, int divisor, int& remainder);

Un altro modo sarebbe quello di dichiarare una struttura per contenere tutti i risultati e restituire che:

struct divide_result {
    int quotient;
    int remainder;
};

divide_result divide(int dividend, int divisor);

Uno di questi modi è generalmente preferito o ci sono altri suggerimenti?

Modifica: nel codice del mondo reale, potrebbero esserci più di due risultati. Possono anche essere di diversi tipi.

Risposte:


217

Per restituire due valori uso un std::pair(di solito digitato). Dovresti guardare boost::tuple(in C ++ 11 e più recenti, c'è std::tuple) per più di due risultati di ritorno.

Con l'introduzione dell'associazione strutturata in C ++ 17, il ritorno std::tupledovrebbe probabilmente diventare uno standard accettato.


12
+1 per la tupla. Tenere presente le ramificazioni delle prestazioni di oggetti di grandi dimensioni che ritornano in una struttura anziché passare per riferimento.
Marcin,

12
Se hai intenzione di usare le tuple, perché non usarle anche per le coppie. Perché avere un caso speciale?
Ferruccio,

4
Fred, sì boost :: la tupla può farlo :)
Johannes Schaub - litb,

46
In C ++ 11, è possibile utilizzare std::tuple.
Ferruccio,

14
Se si desidera accettare più valori da una funzione, un modo conveniente per farlo è quello di utilizzare std::tie stackoverflow.com/a/2573822/502144
fdermishin

176

In C ++ 11 puoi:

#include <tuple>

std::tuple<int, int> divide(int dividend, int divisor) {
    return  std::make_tuple(dividend / divisor, dividend % divisor);
}

#include <iostream>

int main() {
    using namespace std;

    int quotient, remainder;

    tie(quotient, remainder) = divide(14, 3);

    cout << quotient << ',' << remainder << endl;
}

In C ++ 17:

#include <tuple>

std::tuple<int, int> divide(int dividend, int divisor) {
    return  {dividend / divisor, dividend % divisor};
}

#include <iostream>

int main() {
    using namespace std;

    auto [quotient, remainder] = divide(14, 3);

    cout << quotient << ',' << remainder << endl;
}

o con strutture:

auto divide(int dividend, int divisor) {
    struct result {int quotient; int remainder;};
    return result {dividend / divisor, dividend % divisor};
}

#include <iostream>

int main() {
    using namespace std;

    auto result = divide(14, 3);

    cout << result.quotient << ',' << result.remainder << endl;

    // or

    auto [quotient, remainder] = divide(14, 3);

    cout << quotient << ',' << remainder << endl;
}

4
Ho una preoccupazione per le funzioni che restituiscono tuple. Supponiamo che il prototipo della funzione sopra sia in un'intestazione, quindi come faccio a sapere cosa significano il primo e il secondo valore restituito senza capire la definizione della funzione? quoziente-resto o quoziente-resto.
Uchia Itachi,

7
@UchiaItachi Stessa preoccupazione per i parametri delle funzioni, puoi dare loro dei nomi, ma la lingua non lo impone nemmeno e i nomi dei parametri non hanno alcun valore nel sito di chiamata durante la lettura. Inoltre, su un singolo ritorno, hai solo un tipo, ma avere il nome potrebbe anche essere utile, con le tuple raddoppi il problema, quindi, il linguaggio manca solo di auto-documentarsi in diversi modi, non solo.
pepper_chico,

1
come sarebbe l'ultimo esempio se volessi specificare esplicitamente il tipo di ritorno di divide ()? Devo quindi definire il risultato da qualche altra parte o posso definirlo proprio nella specifica del tipo di ritorno?
Slava,

1
@Slava non puoi definire un tipo proprio alla firma della funzione, dovresti dichiararlo all'esterno e usarlo come tipo di ritorno, come è normalmente fatto (basta spostare la structlinea fuori dal corpo della funzione e sostituire la autofunzione return con result.
pepper_chico,

3
@pepper_chico Cosa succede se si desidera inserire la definizione della funzione dividein un file cpp separato? Ottengo l'errore error: use of ‘auto divide(int, int)’ before deduction of ‘auto’. Come lo risolvo?
Adriaan,

123

Personalmente, in genere non mi piacciono i parametri di ritorno per una serie di motivi:

  • non è sempre ovvio nell'invocazione quali parametri sono interni e quali esterni
  • generalmente devi creare una variabile locale per catturare il risultato, mentre i valori di ritorno possono essere usati in linea (che può essere o non essere una buona idea, ma almeno hai l'opzione)
  • mi sembra più pulito avere una "porta dentro" e una "porta fuori" per una funzione - tutti gli ingressi entrano qui, tutte le uscite escono là
  • Mi piace mantenere il mio elenco di argomenti il ​​più breve possibile

Ho anche alcune riserve sulla tecnica coppia / tupla. Principalmente, spesso non esiste un ordine naturale per i valori di ritorno. In che modo il lettore del codice può sapere se result.first è il quoziente o il resto? E l'implementatore potrebbe cambiare l'ordine, il che spezzerebbe il codice esistente. Ciò è particolarmente insidioso se i valori sono dello stesso tipo in modo che non vengano generati errori o avvisi del compilatore. In realtà, questi argomenti si applicano anche ai parametri di ritorno.

Ecco un altro esempio di codice, questo un po 'meno banale:

pair<double,double> calculateResultingVelocity(double windSpeed, double windAzimuth,
                                               double planeAirspeed, double planeCourse);

pair<double,double> result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.first << endl;
cout << result.second << endl;

Questa stampa indica la velocità di avanzamento e la rotta, oppure la rotta e la velocità di avanzamento? Non è ovvio

Confronta con questo:

struct Velocity {
    double speed;
    double azimuth;
};
Velocity calculateResultingVelocity(double windSpeed, double windAzimuth,
                                    double planeAirspeed, double planeCourse);

Velocity result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.speed << endl;
cout << result.azimuth << endl;

Penso che questo sia più chiaro.

Quindi penso che la mia prima scelta in generale sia la tecnica struct. L'idea di coppia / tupla è probabilmente un'ottima soluzione in alcuni casi. Vorrei evitare i parametri di ritorno quando possibile.


1
Il suggerimento di dichiarare un structlike Velocityè carino. Tuttavia, una preoccupazione è che inquina lo spazio dei nomi. Suppongo che con C ++ 11, structpuò avere un nome di tipo lungo e uno può usare auto result = calculateResultingVelocity(...).
Hugues,

5
+1. Una funzione dovrebbe restituire una "cosa", non una "tupla di cose" ordinata in qualche modo.
DevSolar,

1
Preferisco le strutture rispetto a std :: accoppiamenti / std :: tuple per i motivi descritti in questa risposta. Ma non mi piace anche lo spazio dei nomi "inquinamento". La soluzione ideale per me sarebbe restituire una struttura anonima come struct { int a, b; } my_func();. Questo potrebbe essere utilizzato come questo: auto result = my_func();. Ma C ++ non lo consente: "i nuovi tipi non possono essere definiti in un tipo restituito". Quindi devo creare strutture come struct my_func_result_t...
anton_rh

2
@anton_rh: C ++ 14 consente di restituire i tipi locali con auto, quindi auto result = my_func();è banalmente ottenibile.
ildjarn,

4
Circa 15 anni fa, quando scoprimmo il boost, usavamo molto la tupla poiché è abbastanza utile. Nel lavoro straordinario abbiamo riscontrato lo svantaggio della leggibilità, in particolare per le tuple dello stesso tipo (ad es. Tupla <doppia, doppia>; quale è quale). Quindi ultimamente abbiamo più l'abitudine di introdurre una piccola struttura POD in cui almeno il nome della variabile membro indica qualcosa di sensato.
gast128,

24
std::pair<int, int> divide(int dividend, int divisor)
{
   // :
   return std::make_pair(quotient, remainder);
}

std::pair<int, int> answer = divide(5,2);
 // answer.first == quotient
 // answer.second == remainder

std :: pair è essenzialmente la tua soluzione struct, ma già definita per te e pronta ad adattarsi a due tipi di dati.


3
Funzionerà con il mio semplice esempio. In generale, tuttavia, potrebbero essere restituiti più di due valori.
Fred Larson,

5
Inoltre non auto-documentante. Riesci a ricordare quale registro x86 è il resto di DIV?
Segna il

1
@Mark - Concordo sul fatto che le soluzioni posizionali possono essere meno gestibili. È possibile riscontrare il problema "permuta e confondere".
Fred Larson,

16

Dipende interamente dalla funzione effettiva e dal significato dei valori multipli e dalle loro dimensioni:

  • Se sono correlati come nel tuo esempio di frazione, sceglierei un'istanza di tipo struct o class.
  • Se non sono realmente correlati e non possono essere raggruppati in una classe / struttura, forse dovresti riformattare il tuo metodo in due.
  • A seconda della dimensione in memoria dei valori che stai restituendo, potresti voler restituire un puntatore a un'istanza o struttura di una classe o utilizzare parametri di riferimento.

1
Mi piace la tua risposta e il tuo ultimo proiettile mi ricorda qualcosa che ho appena letto che passare per valore è diventato molto più veloce a seconda delle circostanze che lo rendono più complicato ... cpp-next.com/archive/2009/08/want-speed-pass -per valore
saggio il

12

La soluzione OO per questo è creare una classe di rapporto. Non richiederebbe alcun codice aggiuntivo (ne risparmierebbe un po '), sarebbe significativamente più pulito / chiaro e ti darebbe alcuni refactoring extra che ti permetteranno di ripulire il codice anche al di fuori di questa classe.

In realtà penso che qualcuno abbia raccomandato di restituire una struttura, che è abbastanza vicina ma nasconde l'intento che questa deve essere una classe completamente pensata con costruttore e alcuni metodi, in effetti il ​​"metodo" che hai menzionato in origine (come restituire il coppia) dovrebbe probabilmente essere un membro di questa classe che restituisce un'istanza di se stessa.

So che il tuo esempio era solo un "Esempio", ma il fatto è che, a meno che la tua funzione non vada molto più di quanto dovrebbe fare qualsiasi funzione, se vuoi che restituisca più valori quasi sicuramente ti manca un oggetto.

Non aver paura di creare queste minuscole classi per fare piccoli lavori - questa è la magia di OO - finisci per scomporlo fino a quando ogni metodo è molto piccolo e semplice e ogni classe piccola e comprensibile.

Un'altra cosa che avrebbe dovuto essere un indicatore del fatto che qualcosa non andava: in OO non hai essenzialmente dati - OO non riguarda il passaggio di dati, una classe deve gestire e manipolare i propri dati internamente, qualsiasi passaggio di dati (inclusi gli accessori) è un segnale che potrebbe essere necessario ripensare qualcosa ..


10

Esiste un precedente per restituire strutture nello standard C (e quindi C ++) con le funzioni div, ldiv(e, in C99, lldiv) da <stdlib.h>(o <cstdlib>).

Il "mix di valore di ritorno e parametri di ritorno" è generalmente il meno pulito.

Avere una funzione restituisce uno stato e restituisce i dati tramite i parametri di ritorno è sensato in C; è ovviamente meno sensato in C ++ in cui è possibile utilizzare le eccezioni per inoltrare informazioni sugli errori.

Se ci sono più di due valori di ritorno, probabilmente è meglio un meccanismo simile a una struttura.


10

Con C ++ 17 è anche possibile restituire uno o più valori non immobili / non riparabili (in alcuni casi). La possibilità di restituire tipi inamovibili deriva dalla nuova ottimizzazione del valore di ritorno garantito, che si adatta perfettamente agli aggregati e ai cosiddetti costruttori basati su modelli .

template<typename T1,typename T2,typename T3>
struct many {
  T1 a;
  T2 b;
  T3 c;
};

// guide:
template<class T1, class T2, class T3>
many(T1, T2, T3) -> many<T1, T2, T3>;

auto f(){ return many{string(),5.7, unmovable()}; }; 

int main(){
   // in place construct x,y,z with a string, 5.7 and unmovable.
   auto [x,y,z] = f();
}

La cosa bella di questo è che è garantito che non causerà alcuna copia o spostamento. Puoi fare l'esempiomany struct variadic. Più dettagli:

Restituzione di aggregati variadici (struct) e sintassi per il modello C ++ 17 variadic 'guida alla deduzione della costruzione'


6

Esistono diversi modi per restituire più parametri. Ho intenzione di essere esausto.

Usa parametri di riferimento:

void foo( int& result, int& other_result );

utilizzare i parametri del puntatore:

void foo( int* result, int* other_result );

che ha il vantaggio che devi fare a & chiamata sul sito di chiamata, avvertendo eventualmente le persone che è un parametro fuori parametro.

Scrivi un modello e usalo:

template<class T>
struct out {
  std::function<void(T)> target;
  out(T* t):target([t](T&& in){ if (t) *t = std::move(in); }) {}
  out(std::optional<T>* t):target([t](T&& in){ if (t) t->emplace(std::move(in)); }) {}
  out(std::aligned_storage_t<sizeof(T), alignof(T)>* t):
    target([t](T&& in){ ::new( (void*)t ) T(std::move(in)); } ) {}
  template<class...Args> // TODO: SFINAE enable_if test
  void emplace(Args&&...args) {
    target( T(std::forward<Args>(args)...) );
  }
  template<class X> // TODO: SFINAE enable_if test
  void operator=(X&&x){ emplace(std::forward<X>(x)); }
  template<class...Args> // TODO: SFINAE enable_if test
  void operator()(Args...&&args){ emplace(std::forward<Args>(args)...); }
};

allora possiamo fare:

void foo( out<int> result, out<int> other_result )

e tutto va bene. foonon è più in grado di leggere alcun valore trasmesso come bonus.

Altri modi per definire un punto in cui è possibile inserire i dati possono essere utilizzati per costruire out. Un callback per posizionare le cose da qualche parte, per esempio.

Possiamo restituire una struttura:

struct foo_r { int result; int other_result; };
foo_r foo();

whick funziona bene in ogni versione di C ++ e in ciò consente anche:

auto&&[result, other_result]=foo();

a costo zero. I parametri non possono nemmeno essere spostati grazie all'elisione garantita.

Potremmo restituire un std::tuple:

std::tuple<int, int> foo();

che ha il rovescio della medaglia che i parametri non sono nominati. Questo permette al:

auto&&[result, other_result]=foo();

anche. Precedente a possiamo invece fare:

int result, other_result;
std::tie(result, other_result) = foo();

che è solo un po 'più imbarazzante. L'elisione garantita non funziona qui, tuttavia.

Andando in un territorio sconosciuto (e questo dopo out<>!), Possiamo usare lo stile di passaggio di continuazione:

void foo( std::function<void(int result, int other_result)> );

e ora i chiamanti fanno:

foo( [&](int result, int other_result) {
  /* code */
} );

un vantaggio di questo stile è che puoi restituire un numero arbitrario di valori (con tipo uniforme) senza dover gestire la memoria:

void get_all_values( std::function<void(int)> value )

il valuecallback potrebbe essere chiamato 500 volte quando tu get_all_values( [&](int value){} ).

Per pura follia, potresti persino usare una continuazione sulla continuazione.

void foo( std::function<void(int, std::function<void(int)>)> result );

il cui uso è simile a:

foo( [&](int result, auto&& other){ other([&](int other){
  /* code */
}) });

che consentirebbe molte relazioni tra resulte other.

Ancora una volta con valori uniforniani, possiamo farlo:

void foo( std::function< void(span<int>) > results )

qui, chiamiamo il callback con un arco di risultati. Possiamo persino farlo ripetutamente.

Usando questo, puoi avere una funzione che passa in modo efficiente megabyte di dati senza fare alcuna allocazione dallo stack.

void foo( std::function< void(span<int>) > results ) {
  int local_buffer[1024];
  std::size_t used = 0;
  auto send_data=[&]{
    if (!used) return;
    results({ local_buffer, used });
    used = 0;
  };
  auto add_datum=[&](int x){
    local_buffer[used] = x;
    ++used;
    if (used == 1024) send_data();
  };
  auto add_data=[&](gsl::span<int const> xs) {
    for (auto x:xs) add_datum(x);
  };
  for (int i = 0; i < 7+(1<<20); ++i) {
    add_datum(i);
  }
  send_data(); // any leftover
}

Ora, std::functionè un po 'pesante per questo, come lo faremmo in ambienti senza allocazione a zero spese. Quindi vorremmo un function_viewche non alloca mai.

Un'altra soluzione è:

std::function<void(std::function<void(int result, int other_result)>)> foo(int input);

dove invece di prendere il callback e invocarlo, foorestituisce invece una funzione che accetta il callback.

foo (7) ([&] (int result, int other_result) {/ * code * /}); questo interrompe i parametri di output dai parametri di input avendo parentesi separate.

Con variantecoroutine, potresti creare fooun generatore di una variante dei tipi restituiti (o solo del tipo restituito). La sintassi non è ancora stata risolta, quindi non fornirò esempi.

Nel mondo dei segnali e degli slot, una funzione che espone un insieme di segnali:

template<class...Args>
struct broadcaster;

broadcaster<int, int> foo();

consente di creare un oggetto fooche funziona in modo asincrono e trasmette il risultato al termine.

In questa linea abbiamo una varietà di tecniche di pipeline, in cui una funzione non fa qualcosa ma piuttosto organizza la connessione dei dati in qualche modo, e il fare è relativamente indipendente.

foo( int_source )( int_dest1, int_dest2 );

quindi questo codice non fa nulla fino a quando non int_sourceha numeri interi per fornirlo. Quando lo fa, int_dest1e int_dest2inizia a ricevere i risultati.


Questa risposta contiene più informazioni di altre risposte! in particolare, informazioni su auto&&[result, other_result]=foo();per funzioni che restituiscono sia tuple che strutture. Grazie!
jjmontes,

Apprezzo questa risposta esaustiva, soprattutto perché sono ancora bloccato con C ++ 11 e quindi non posso usare alcune delle soluzioni più moderne che altre persone propongono.
GuyGizmo,

5

Utilizzare una struttura o una classe per il valore restituito. L'uso std::pairpotrebbe funzionare per ora, ma

  1. non è flessibile se decidi in seguito di voler restituire ulteriori informazioni;
  2. dalla dichiarazione della funzione nell'intestazione non è molto chiaro cosa viene restituito e in quale ordine.

Restituire una struttura con nomi di variabili membro autocompensanti sarà probabilmente meno soggetto a bug per chiunque utilizzi la tua funzione. Indossando il mio cappello da collega per un momento, la tua divide_resultstruttura è facile per me, un potenziale utente della tua funzione, da capire immediatamente dopo 2 secondi. Fare casino con i parametri di uscita o coppie e tuple misteriose richiederebbe più tempo per leggere e potrebbe essere usato in modo errato. E molto probabilmente anche dopo aver usato la funzione alcune volte non ricordo ancora l'ordine corretto degli argomenti.


4

Se la tua funzione restituisce un valore tramite riferimento, il compilatore non può memorizzarlo in un registro quando chiama altre funzioni perché, in teoria, la prima funzione può salvare l'indirizzo della variabile passata ad essa in una variabile accessibile globalmente e qualsiasi funzione chiamata in modo secondario può cambiarlo, quindi il compilatore dovrà (1) salvare il valore dai registri nella memoria prima di richiamare altre funzioni e (2) rileggerlo quando è necessario nuovamente dalla memoria dopo una di tali chiamate.

Se ritorni per riferimento, l'ottimizzazione del tuo programma ne risentirà


4

Qui, sto scrivendo un programma che sta restituendo più valori (più di due valori) in c ++. Questo programma è eseguibile in c ++ 14 (G ++ 4.9.2). il programma è come una calcolatrice.

#  include <tuple>
# include <iostream>

using namespace std; 

tuple < int,int,int,int,int >   cal(int n1, int n2)
{
    return  make_tuple(n1/n2,n1%n2,n1+n2,n1-n2,n1*n2);
}

int main()
{
    int qut,rer,add,sub,mul,a,b;
    cin>>a>>b;
    tie(qut,rer,add,sub,mul)=cal(a,b);
    cout << "quotient= "<<qut<<endl;
    cout << "remainder= "<<rer<<endl;
    cout << "addition= "<<add<<endl;
    cout << "subtraction= "<<sub<<endl;
    cout << "multiplication= "<<mul<<endl;
    return 0;
}

Quindi, puoi capire chiaramente che in questo modo puoi restituire più valori da una funzione. usando std :: pair possono essere restituiti solo 2 valori mentre std :: tuple può restituire più di due valori.


4
Con C ++ 14 puoi anche usare il autotipo return su calper rendere questo ancora più pulito. (IMO).
sfjac,

3

Tendo a usare valori esagerati in funzioni come questa, perché mi attengo al paradigma di una funzione che restituisce codici di successo / errore e mi piace mantenere le cose uniformi.


2

Le alternative includono array, generatori e inversione di controllo , ma qui non è appropriato.

Alcuni (ad es. Microsoft nella storica Win32) tendono ad usare i parametri di riferimento per semplicità, perché è chiaro chi alloca e come apparirà nello stack, riduce la proliferazione delle strutture e consente un valore di ritorno separato per il successo.

I programmatori "puri" preferiscono la struttura, supponendo che sia il valore della funzione (come nel caso qui), piuttosto che qualcosa che viene toccato per inciso dalla funzione. Se avessi una procedura più complicata, o qualcosa con stato, probabilmente useresti riferimenti (supponendo che tu abbia una ragione per non usare una classe).


2

Direi che non esiste un metodo preferito, tutto dipende da cosa hai intenzione di fare con la risposta. Se i risultati verranno usati insieme in un'ulteriore elaborazione, allora le strutture hanno un senso, se no tenderei a passare come riferimenti individuali a meno che la funzione non fosse utilizzata in un'istruzione composita:

x = divide( x, y, z ) + divide( a, b, c );

Scelgo spesso di passare "strutture" per riferimento nell'elenco dei parametri piuttosto che avere il passaggio per overhead di copia per restituire una nuova struttura (ma questo è sudare le piccole cose).

void divide(int dividend, int divisor, Answer &ans)

I parametri sono confusi? Un parametro inviato come riferimento suggerisce che il valore cambierà (al contrario di un riferimento const). La denominazione sensibile rimuove anche la confusione.


1
Penso che sia un po 'confuso. Qualcuno che legge il codice che lo chiama vede "divide (a, b, c);". Non c'è alcuna indicazione che c sia un outval finché non cercano la firma. Ma questa è una paura generale per i parametri di riferimento non costanti, piuttosto che particolare per questa domanda.
Steve Jessop,

2

Perché insisti su una funzione con più valori di ritorno? Con OOP è possibile utilizzare una classe che offre una funzione regolare con un singolo valore restituito e un numero qualsiasi di "valori restituiti" aggiuntivi come di seguito. Il vantaggio è che il chiamante può scegliere di guardare i membri di dati extra, ma non è tenuto a farlo. Questo è il metodo preferito per chiamate di rete o chiamate di rete complicate, in cui potrebbero essere necessarie molte informazioni di restituzione aggiuntive in caso di errori.

Per rispondere alla domanda originale, questo esempio ha un metodo per restituire il quoziente, che è ciò di cui potrebbe aver bisogno la maggior parte dei chiamanti, e inoltre, dopo la chiamata del metodo, è possibile ottenere il resto come membro di dati.

class div{
   public:
      int remainder;

      int quotient(int dividend, int divisor){
         remainder = ...;
         return ...;
      }
};

1
Penso che ci siano casi in cui questo è inefficiente. Ad esempio, hai un singolo ciclo for che genera diversi valori di ritorno. Se dividi questi valori in funzioni separate, dovrai eseguire il ciclo una volta per ogni valore.
jiggunjer

1
@jiggunjer È possibile eseguire il ciclo una volta e memorizzare i diversi valori di ritorno in membri di dati di classe separati. Ciò sottolinea la flessibilità del concetto OOP.
Roland

2

anziché restituire più valori, basta restituire uno di essi e fare un riferimento ad altri nella funzione richiesta, ad esempio:

int divide(int a,int b,int quo,int &rem)

Non l'ho menzionato nella domanda stessa? Inoltre, vedi le mie obiezioni nella mia risposta .
Fred Larson,

1

Aumentare la tupla sarebbe la mia scelta preferita per un sistema generalizzato di restituzione di più di un valore da una funzione.

Esempio possibile:

include "boost/tuple/tuple.hpp"

tuple <int,int> divide( int dividend,int divisor ) 

{
  return make_tuple(dividend / divisor,dividend % divisor )
}

1

Possiamo dichiarare la funzione in modo tale che restituisca una variabile definita dall'utente di tipo struttura o un puntatore ad essa. E per la proprietà di una struttura, sappiamo che una struttura in C può contenere più valori di tipi asimmetrici (cioè una variabile int, quattro variabili char, due variabili float e così via ...)


1

Lo farei solo per riferimento se fosse solo qualche valore di ritorno ma per tipi più complessi puoi anche farlo in questo modo:

static struct SomeReturnType {int a,b,c; string str;} SomeFunction()
{
  return {1,2,3,string("hello world")}; // make sure you return values in the right order!
}

utilizzare "statico" per limitare l'ambito del tipo restituito a questa unità di compilazione se si intende solo un tipo restituito temporaneo.

 SomeReturnType st = SomeFunction();
 cout << "a "   << st.a << endl;
 cout << "b "   << st.b << endl;
 cout << "c "   << st.c << endl;
 cout << "str " << st.str << endl;

Questo non è sicuramente il modo più carino per farlo, ma funzionerà.


-2

Ecco un esempio completo di questo tipo di soluzione del problema

#include <bits/stdc++.h>
using namespace std;
pair<int,int> solve(int brr[],int n)
{
    sort(brr,brr+n);

    return {brr[0],brr[n-1]};
}

int main()
{
    int n;
    cin >> n;
    int arr[n];
    for(int i=0; i<n; i++)
    {
        cin >> arr[i];
    }

    pair<int,int> o=solve(arr,n);
    cout << o.first << " " << o.second << endl;

    return 0;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.