Valore predefinito per un parametro durante il passaggio per riferimento in C ++

È ansible assegnare un valore predefinito a un parametro di una funzione mentre si passa il parametro per riferimento. in C ++

Ad esempio, quando provo a dichiarare una funzione come:

virtual const ULONG Write(ULONG &State = 0, bool sequence = true); 

Quando faccio questo dà un errore:

errore C2440: ‘argomento predefinito’: imansible convertire da ‘const int’ a ‘unsigned long &’ Un riferimento che non è ‘const’ non può essere associato a un non-lvalue

    Puoi farlo per un riferimento const, ma non per uno non const. Questo perché C ++ non consente a un temporaneo (il valore predefinito in questo caso) di essere associato a un riferimento non const.

    Un modo per aggirare questo sarebbe utilizzare un’istanza reale come predefinita:

     static int AVAL = 1; void f( int & x = AVAL ) { // stuff } int main() { f(); // equivalent to f(AVAL); } 

    ma questo è di uso pratico molto limitato.

    È già stato detto in uno dei commenti diretti alla tua risposta, ma solo per dichiararlo ufficialmente. Quello che vuoi usare è un sovraccarico:

     virtual const ULONG Write(ULONG &State, bool sequence); inline const ULONG Write() { ULONG state; bool sequence = true; Write (state, sequence); } 

    Anche l’utilizzo degli overload di funzioni ha ulteriori vantaggi. Innanzitutto puoi impostare come predefinito qualsiasi argomento che desideri:

     class A {}; class B {}; class C {}; void foo (A const &, B const &, C const &); void foo (B const &, C const &); // A defaulted void foo (A const &, C const &); // B defaulted void foo (C const &); // A & B defaulted etc... 

    È anche ansible ridefinire gli argomenti predefiniti per le funzioni virtuali nella class derivata, che l’overloading evita:

     class Base { public: virtual void f1 (int i = 0); // default '0' virtual void f2 (int); inline void f2 () { f2(0); // equivalent to default of '0' } }; class Derived : public Base{ public: virtual void f1 (int i = 10); // default '10' using Base::f2; virtual void f2 (int); }; void bar () { Derived d; Base & b (d); d.f1 (); // '10' used b.f1 (); // '0' used d.f2 (); // f1(int) called with '0' b.f2 (); // f1(int) called with '0 } 

    Esiste solo una situazione in cui è necessario utilizzare un valore predefinito e questo è su un costruttore. Non è ansible chiamare un costruttore da un altro, e quindi questa tecnica non funziona in quel caso.

    C’è ancora il vecchio modo C di fornire argomenti opzionali: un puntatore che può essere NULL se non presente:

     void write( int *optional = 0 ) { if (optional) *optional = 5; } 

    Questo piccolo modello ti aiuterà:

     template class ByRef { public: ByRef() { } ByRef(const T value) : mValue(value) { } operator T&() const { return((T&)mValue); } private: T mValue; }; 

    Allora sarai in grado di:

     virtual const ULONG Write(ULONG &State = ByRef(0), bool sequence = true); 

    Ci sono due ragioni per passare un argomento per riferimento: (1) per le prestazioni (nel qual caso si desidera passare con riferimento const) e (2) perché è necessario modificare il valore dell’argomento all’interno della funzione.

    Dubito fortemente che passare un lungo periodo senza firma su architetture moderne ti stia rallentando troppo. Quindi presumo che tu abbia intenzione di cambiare il valore dello State all’interno del metodo. Il compilatore si lamenta perché la costante 0 non può essere modificata, poiché è un valore rvalue (“non-lvalue” nel messaggio di errore) e non modificabile ( const nel messaggio di errore).

    In poche parole, vuoi un metodo che può cambiare l’argomento passato, ma per impostazione predefinita vuoi passare un argomento che non può cambiare.

    Per dirla in altro modo, i riferimenti non const devono fare riferimento a variabili reali. Il valore predefinito nella firma della funzione ( 0 ) non è una variabile reale. Stai incontrando lo stesso problema di:

     struct Foo { virtual ULONG Write(ULONG& State, bool sequence = true); }; Foo f; ULONG s = 5; f.Write(s); // perfectly OK, because s is a real variable f.Write(0); // compiler error, 0 is not a real variable // if the value of 0 were changed in the function, // I would have no way to refer to the new value 

    Se in realtà non si intende modificare lo State all’interno del metodo, è sufficiente modificarlo in const ULONG& . Ma non otterrai grandi vantaggi in termini di prestazioni, quindi ti consiglio di cambiarlo in un ULONG non di riferimento. Ho notato che stai già restituendo ULONG , e ho il minimo sospetto che il suo valore sia il valore di State dopo ogni modifica necessaria. In tal caso, dichiarerei semplicemente il metodo in questo modo:

     // returns value of State virtual ULONG Write(ULONG State = 0, bool sequence = true); 

    Certo, non sono abbastanza sicuro di cosa stai scrivendo o dove. Ma questa è un’altra domanda per un’altra volta.

    Non è ansible utilizzare un valore letterale costante per un parametro predefinito per lo stesso motivo per cui non è ansible utilizzarne uno come parametro per la chiamata di funzione. I valori di riferimento devono avere un indirizzo, i valori dei riferimenti costanti non devono (cioè possono essere valori r o letterali costanti).

     int* foo (int& i ) { return &i; } foo(0); // compiler error. const int* bar ( const int& i ) { return &i; } bar(0); // ok. 

    Assicurati che il tuo valore predefinito abbia un indirizzo e che tu stia bene.

     int null_object = 0; int Write(int &state = null_object, bool sequence = true) { if( &state == &null_object ) { // called with default paramter return sequence? 1: rand(); } else { // called with user parameter state += sequence? 1: rand(); return state; } } 

    Ho usato questo schema un paio di volte in cui ho avuto un parametro che potrebbe essere una variabile o null. L’approccio normale consiste nel far passare l’utente in un puntatore, questo è il caso. Passano in un puntatore NULL se non vogliono che tu inserisca il valore. Mi piace l’approccio all’object null. Rende la vita dei chiamanti più facile senza complicare terribilmente il codice di chiamata.

    No, non è ansible.

    Il passaggio per riferimento implica che la funzione potrebbe modificare il valore del parametro. Se il parametro non è fornito dal chiamante e proviene dalla costante predefinita, qual è la funzione che si suppone cambierà?

    Penso di no, e il motivo è che i valori predefiniti vengono valutati per le costanti ei valori passati per riferimento devono essere in grado di cambiare, a meno che non si dichiari anche che si tratta di un riferimento costante.

    Un altro modo potrebbe essere il seguente:

     virtual const ULONG Write(ULONG &State, bool sequence = true); // wrapper const ULONG Write(bool sequence = true) { ULONG dummy; return Write(dummy, sequence); } 

    quindi sono possibili le seguenti chiamate:

     ULONG State; object->Write(State, false); // sequence is false, "returns" State object->Write(State); // assumes sequence = true, "returns" State object->Write(false); // sequence is false, no "return" object->Write(); // assumes sequence = true, no "return" 
     void f(const double& v = *(double*) NULL) { if (&v == NULL) cout << "default" << endl; else cout << "other " << v << endl; } 

    In caso di OO … Dire che una Data Class ha e “Default” significa che questo Default (valore) deve essere dichiarato acondingly e quindi può essere usato come parametro predefinito ex:

     class Pagination { public: int currentPage; //... Pagination() { currentPage = 1; //... } // your Default Pagination static Pagination& Default() { static Pagination pag; return pag; } }; 

    Sul tuo metodo …

      shared_ptr > findByFilter(Auditoria& audit, Pagination& pagination = Pagination::Default() ) { 

    Questa soluzione è abbastanza adatta poiché in questo caso, “Impaginazione predefinita globale” è un singolo valore di “riferimento”. Avrai anche la possibilità di modificare i valori predefiniti in fase di esecuzione come una configurazione “gobal-level” ex: preferenze di navigazione di impaginazione utente ed ecc.

    È ansible con qualificatore const per State:

     virtual const ULONG Write(const ULONG &State = 0, bool sequence = true); 
     void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false); 

    C’è anche un trucco piuttosto sporco per questo:

     virtual const ULONG Write(ULONG &&State = 0, bool sequence = true); 

    In questo caso devi chiamarlo con std::move :

     ULONG val = 0; Write(std::move(val)); 

    È solo una soluzione divertente, non consiglio assolutamente di usarlo nel codice reale!

    virtual const ULONG Write (ULONG & State = 0, bool sequence = true);

    La risposta è abbastanza semplice e non sono così bravo a spiegare, ma se si vuole passare un valore predefinito ad un parametro non-const che probabilmente verrà modificato in questa funzione è come usarlo in questo modo:

     virtual const ULONG Write(ULONG &State = *(ULONG*)0, bool sequence = > true);