Standardwert für einen Parameter bei der Übergabe als Verweis in C ++

Ist es möglich, einem Parameter einer function einen Standardwert zuzuweisen, während wir den Parameter als Referenz übergeben? in C ++

Zum Beispiel, wenn ich versuche, eine function wie zu deklarieren:

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

Wenn ich das mache, gibt es einen Fehler:

Fehler C2440: ‘Standardargument’: Konvertierung von ‘const int’ in ‘unsigned long &’ nicht möglich Eine Referenz, die nicht ‘const’ ist, kann nicht an einen Nicht-Lvalue gebunden werden

    Sie können dies für eine const-Referenz tun, aber nicht für eine nicht-konstante. Dies liegt daran, dass C ++ es nicht erlaubt, dass ein temporärer Wert (der Standardwert in diesem Fall) an eine nicht-konstante Referenz gebunden wird.

    Eine Möglichkeit wäre, eine tatsächliche Instanz als Standard zu verwenden:

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

    aber dies ist von sehr begrenztem praktischen Nutzen.

    Es wurde bereits in einem der direkten Kommentare zu Ihrer Antwort gesagt, aber nur um es offiziell zu sagen. Was Sie verwenden möchten, ist eine Überladung:

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

    Die Verwendung von functionsüberlastungen hat auch zusätzliche Vorteile. Erstens können Sie jedes beliebige Argument voreinstellen:

     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... 

    Es ist auch möglich, Standardargumente für virtuelle functionen in der abgeleiteten class neu zu definieren, was das Überladen vermeidet:

     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 } 

    Es gibt nur eine Situation, in der wirklich ein Standard verwendet werden muss, und das gilt für einen Konstruktor. Es ist nicht möglich, einen Konstruktor von einem anderen zu rufen, und daher funktioniert diese Technik in diesem Fall nicht.

    Es gibt immer noch die alte C-Methode, die optionale Argumente liefert: ein pointers, der NULL sein kann, wenn er nicht vorhanden ist:

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

    Diese kleine Vorlage wird Ihnen helfen:

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

    Dann können Sie:

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

    Es gibt zwei Gründe, ein Argument durch Verweis zu übergeben: (1) für die performance (in diesem Fall möchten Sie die Konstante const übergeben) und (2), weil Sie die Möglichkeit haben müssen, den Wert des Arguments innerhalb der function zu ändern.

    Ich bezweifle sehr, dass das Überschreiten einer unsignierten Lange auf modernen Architekturen Sie zu sehr verlangsamt. Ich gehe also davon aus, dass Sie beabsichtigen, den Wert von State innerhalb der Methode zu ändern. Der Compiler beschweren sich, weil die Konstante 0 nicht geändert werden kann, da es sich um einen Rvalue (“nicht-lvalue” in der Fehlermeldung) und unveränderbar ( const in der Fehlermeldung) handelt.

    Einfach ausgedrückt, Sie möchten eine Methode, die das übergebene Argument ändern kann, aber standardmäßig möchten Sie ein Argument übergeben, das nicht geändert werden kann.

    Um es anders const : Nicht- const Referenzen müssen sich auf tatsächliche Variablen beziehen. Der Standardwert in der functionssignatur ( 0 ) ist keine reelle Variable. Sie stoßen auf das gleiche Problem wie:

     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 

    Wenn Sie den const ULONG& innerhalb der Methode nicht wirklich ändern const ULONG& können Sie ihn einfach in eine const ULONG& . Aber Sie werden keinen großen performancesvorteil daraus ziehen, also würde ich empfehlen, es zu einem Nicht-Referenz- ULONG . Ich ULONG , dass du bereits einen ULONG , und ich habe den hinterhältigen Verdacht, dass der Wert des State nach irgendwelchen notwendigen Modifikationen der Wert ist. In diesem Fall würde ich die Methode einfach so erklären:

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

    Natürlich bin ich mir nicht sicher, was du da schreibst oder wohin. Aber das ist eine andere Frage für eine andere Zeit.

    Sie können kein Konstantliteral für einen Standardparameter aus dem gleichen Grund verwenden, den Sie nicht als Parameter für den functionsaufruf verwenden können. Referenzwerte müssen eine Adresse haben, konstante Referenzwerte brauchen nicht (dh sie können r-Werte oder konstante Literale sein).

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

    Stellen Sie sicher, dass der Standardwert eine Adresse hat und es Ihnen gut geht.

     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; } } 

    Ich habe dieses Muster einige Male benutzt, wo ich einen Parameter hatte, der eine Variable oder Null sein konnte. Der normale Ansatz besteht darin, den Benutzer einen pointers übergeben zu lassen, dies ist der Fall. Sie übergeben einen NULL-pointers, wenn sie nicht möchten, dass Sie den Wert eingeben. Ich mag Null-Objekt-Ansatz. Es erleichtert dem Anrufer das Leben, ohne den Angerufenen zu erschrecken.

    Nein, es ist nicht möglich.

    Die Übergabe als Referenz bedeutet, dass die function möglicherweise den Wert des Parameters ändert. Wenn der Parameter nicht vom Aufrufer bereitgestellt wird und von der Standardkonstanten kommt, was soll die function ändern?

    Ich denke nicht, und der Grund ist, dass Standardwerte zu Konstanten ausgewertet werden und Werte, die durch Referenz übergeben werden, in der Lage sein müssen, sich zu ändern, es sei denn, Sie deklarieren es auch als konstante Referenz.

    Ein anderer Weg könnte folgender sein:

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

    dann sind folgende Anrufe möglich:

     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; } 

    Im Falle von OO … Um zu sagen, dass eine gegebene class existiert und “Default” bedeutet, dass dieser Default (Wert) entsprechend deklariert werden muss und dann als Default Parameter exd:

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

    Auf deiner Methode …

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

    Diese Lösung ist sehr geeignet, da in diesem Fall “Globale Standard-Paginierung” ein einzelner “Referenzwert” ist. Sie haben auch die Möglichkeit, Standardwerte zur Laufzeit zu ändern, wie beispielsweise eine Konfiguration auf “Globaler Ebene”, z. B. Benutzerpaginierung, Navigationseinstellungen usw.

    Es ist möglich mit const Qualifier für State:

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

    Es gibt auch einen ziemlich schmutzigen Trick dafür:

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

    In diesem Fall müssen Sie es mit std::move aufrufen:

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

    Es ist nur ein lustiger Workaround, ich empfehle es nicht in echtem Code zu verwenden!

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

    Die Antwort ist ziemlich einfach und ich bin nicht so gut in der Erklärung, aber wenn Sie einen Standardwert an einen nicht-konstanten Parameter übergeben wollen, der wahrscheinlich in dieser function geändert wird, ist es so zu verwenden:

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