2012-11-08 9 views
5

Suppongo che la funzione abbia già un valore di ritorno che non può essere aggiunto.Come posso aggiungere un parametro di uscita a una funzione senza rompere il codice esistente?

Quello che mi è venuto in mente per risolvere questo problema è aggiungere parametri extra del puntatore che di default sono nullptr.

Prima:

bool fun(double a, std::vector<std::randomexample> const & b) 

Dopo:

bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput = nullptr) 

e utilizzarlo come questo

if(extraoutput) 
    *extraoutput = whatever; 

Ma questo è proprio quello che mi è venuta. Mi piacerebbe sapere se c'è un modo migliore per farlo. Nota che "qualunque cosa" è già nella funzione.

+1

Sembra ragionevole. –

+1

Se non si desidera assolutamente modificare la cosa esistente, creare una nuova copia sovraccaricata. –

risposta

4

Se per qualche motivo avete bisogno binario nonché (soprattutto) la compatibilità sorgente [*]:

Prima:

bool fun(double a, std::vector<std::randomexample> const & b) { 
    // do stuff 
    return true; 
} 

Dopo:

bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput) { 
    // do stuff 
    if(extraoutput) 
     *extraoutput = whatever; 
    return true; 
} 
bool fun(double a, std::vector<std::randomexample> const & b) { 
    return fun(a, b, nullptr); 
} 

Se non voglio sovraccaricare le funzioni (ad esempio se fun fa parte di un extern "C" i nterface), quindi non è necessario chiamare la nuova funzione fun. Potrebbe anche essere fun2.

[*] Come sottolinea AndreyT, la compatibilità di origine della soluzione è limitata. Le chiamate alla tua vecchia funzione chiameranno bene la tua nuova funzione, ma alcune altre cose che potresti fare con la vecchia funzione non funzionerebbero bene (dato che hai cambiato il suo tipo).

C'è anche una incompatibilità di origine nel mio codice. void(*foo)() = (void(*)()) fun; è consentito prima che venga aggiunto il sovraccarico, ma in seguito è ambiguo. Se vuoi supportare il codice che lo fa, allora questa è una seconda ragione per non voler sovraccaricare le funzioni.

+0

Perché il tipo di funzione precedente è cambiato? Voglio dire, la vecchia funzione ora chiama solo la nuova funzione in modo che il contenuto sembra essere cambiato, ma non vedo perché il tipo è cambiato. – Sarien

+0

@Corporal: il tipo di funzione 'bool fun (double a, Foo const & b)' è 'bool (double, Foo const &)'. Il tipo di funzione 'bool fun (double a, Foo const & b, int * extraoutput = nullptr)' è 'bool (double, Foo const &, int *)'. I due non sono la stessa cosa. Nel mio codice, c'è ancora una funzione con tipo 'bool (double, Foo const &)' * oltre a * la nuova funzione, quindi il codice che si basa sul vecchio tipo è OK. –

+0

Ah, okay, quindi in realtà non è un problema nella tua soluzione ma nella mia. Mi dispiace, sono confuso. :) – Sarien

-1

È possibile provare a implementare il modello generico di Osservatore. Ecco un esempio: http://sourcemaking.com/design_patterns/observer

Sarà meglio per il futuro quando vorrete aggiungere più parametri. Se non riesci a derivare, anche il passaggio come parametro sarà una soluzione.

Come ho capito, devi farlo in questa funzione, altrimenti si sovraccarico è una buona soluzione.

Non interrompe una compatibilità binaria altrimenti ad altra soluzione.

+1

È davvero rilevante per il caso corrente? –

+0

Una soluzione più generica è sempre un caso, penso per il futuro quando più parametri possono entrare in gioco. – CyberGuy

+0

@ Cthulhu: potrebbe essere. Aggiungi ora un nuovo parametro opzionale, che attualmente ha una funzione 'observewhatever'. Quando accade di nuovo la stessa cosa, non è necessario aggiungere * un altro parametro pointer opzionale alla funzione, è possibile invece aggiungere un'altra funzione all'osservatore. –

0

Come affermato da altri, questo sarà il vostro prodotto finale.

bool fun(double a, std::vector<std::randomexample> const & b){ 
    return fun(a,b,0); 
} 
bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput = 0){ 
    // have fun! 
    if(extraoutput) *extraoutput = whatever; 
    return true; 
} 
+0

perché l'argomento predefinito? – xtofl

+1

In tal caso è necessario rimuovere l'argomento predefinito, poiché altrimenti le chiamate con 2 argomenti diventeranno ambigue. – AnT

+0

Forse sarebbe una buona idea semplicemente creare quell'outputout nella nuova funzione e passarlo come riferimento. Potrebbe essere in grado di salvare alcune copie e la chiamata non sarà più ambigua. – Sarien

2

Normalmente, aggiungo un metodo con il parametro in più, e lo chiamo uno con un valore di default dal primo metodo:

//foo v1 
void foo(S s) { 
    ... stuff with s; 
}; 

//codeA_v1: 
S s; 
foo(s); 

//codeB_v1 
S s2; 
foo(s2); 

Poi, aggiungo un metodo con un parametro aggiuntivo:

void foo(S s){ foo(s, default_value_for_T); } 
void foo(S s, T t){ 
    ... stuff with s and t 
} 

//codeA_v1 == codeA_v2 
S s; 
foo(s); 

//codeB_v2 
S s; 
T t; 
foo(s,t); 
2

Questo è un commento esteso. Come già suggerito dagli altri, è meglio sovraccaricare la funzione per fornire sia la compatibilità di origine che quella binaria. La ragione per farlo è che introducendo una modifica nella firma della funzione, si modifica anche il nome del simbolo di mangler, ad es. da _Z3fundRKSt6vectorISt13randomexampleSaIS0_EE a _Z3fundRKSt6vectorISt13randomexampleSaIS0_EEPi. Ciò interromperà la compatibilità binaria con tutti gli altri oggetti che chiamano fun() dal suo nome storpiato. Se fun() fa parte di una libreria collegata dinamicamente, interromperà tutti i binari esistenti che si collegano ad esso poiché il linker dinamico non sarebbe più in grado di risolvere il riferimento al simbolo _Z3fundRKSt6vectorISt13randomexampleSaIS0_EE. Se si utilizza la versione con funzione sovraccaricata, il vecchio simbolo alterato continuerà a esistere e la compatibilità binaria verrà mantenuta.

Problemi correlati