2015-08-05 3 views
12

Gibt es einen besseren Weg für dieses "Idiom"?Eleganter Weg für "if (T t = ...) {} else return t;"?

if(State s = loadSomething()) { } else return s; 

Mit anderen Worten, ich möchte etwas tun, was einen Fehler (mit einer Nachricht) oder eine Erfolgszustand zurückkehren kann, und wenn es ein Fehler war, ich will es zurück. Das kann sehr repetitiv werden, daher möchte ich es verkürzen. Zum Beispiel

Dies darf keine Ausnahmen verwenden, die ich sonst bevorzugen würde (für diesen Build ungeeignet). Ich könnte eine kleine Klasse BooleanNegator<State> schreiben, die den Wert speichert und seine boolesche Auswertung negiert. Aber ich möchte vermeiden, dass dies ad hoc geschieht, und bevorzuge eine Boost/Standard-Lösung.

+0

I suppo se diesen Staat einen Bool Operator hat, rechts: die Sichtbarkeit kann mit extra {} begrenzt wieder werden? – Brahim

+0

@ Brahim richtig, das ist wahr –

+0

und Sie wollen nicht den Geltungsbereich von 's' außerhalb des' if' Blocks erhöhen, richtig? – CoryKramer

Antwort

10

Sie könnten tun:

for (State s = loadSomething(); !s;) return s; 

aber ich bin nicht sicher, ob es eleganter ist, und es ist auf jeden Fall weniger lesbar ...

+6

zu wickeln Ah ist es definitiv kreativ! –

+11

interessant! :) Aber ich denke, ich würde es nicht gerne im Code sehen, den ich haue: P – quetzalcoatl

3

Ich gehe davon ist der Kontext, so etwas wie

State SomeFunction() 
{ 
    if(State s = loadSomething()) { } else return s; 
    return do_something_else(); 
} 

ohne Ausnahmen zu werfen, wo do_something_else() etwas von Bedeutung für SomeFunction() tut und eine State zurückgibt. In jedem Fall muss das Ergebnis des Fortfahrens in der Funktion dazu führen, dass eine State zurückgegeben wird, da ein Abfallen vom Ende dazu führt, dass der Aufrufer undefiniertes Verhalten zeigt.

In diesem Fall würde ich einfach die Funktion

State SomeFunction() 
{ 
    if (State s = loadSomething()) 
     return do_something_else(); 
    else 
     return s; 
} 

Implizite Annahmen restrukturieren, dass State einige Betreiber hat (zB operator bool()), die getestet werden können, dass ein State Kopieren möglich ist (angedeutet durch die Existenz von einer loadSomething(), die eine zurückgibt) und relativ preiswert, und dass zwei Instanzen von State auf einmal vorhanden sein können.

3

Abgesehen von einigen Smart/Hacky Verwendungen von verschiedenen Schlüsselwörtern, um das gleiche Verhalten zu erhalten, oder Hinzufügen mehr oder weniger komplexe zusätzliche Vorlagen oder Makros, um unless() Schlüsselwort zu bekommen oder irgendwie zu injizieren ! Operator, würde ich bleiben nur die grundlegenden Dinge.

Dies ist einer der Orte, die ich würde (wahrscheinlich) injizieren extra „unnötig“ Klammern:

void someFunction() 
{ 
    // some other code 

    { State s = loadSomething(); if(!s) return s; } 

    // some other code 
} 

jedoch in genau diesem Fall würde ich es erweitern das return Schlüsselwort zu betonen, was leicht übersehen werden kann, wenn es zu einem Einzeiler gequetscht wird. Also, es sei denn, die Einzeiler viele Male wiederholt wird und es sei denn, es ist klar, & offensichtlich, dass es einen return innen, würde ich wahrscheinlich schreiben:

void someFunction() 
{ 
    // some other code 

    { 
     State s = loadSomething(); 
     if(!s) 
      return s; 
    } 

    // some other code 
} 

Es könnte so aussehen, den Umfang der s erhebend, aber es tatsächlich entspricht der Deklaration State s in if(). Alles dank der zusätzlichen Klammern, die die Sichtbarkeit von lokalen s explizit einschränken.

Allerdings "hassen" manche Leute, { .. } nicht mit einem Schlüsselwort/class/function/etc gekoppelt zu sehen, oder halten es sogar für unlesbar, weil "vorgeschlagen wurde, dass ein if/while/etc-Schlüsselwort versehentlich gelöscht wurde".

Eine weitere Idee kam zu mir, nachdem Sie das sich wiederholende Beispiel hinzugefügt haben. Sie könnten einen Trick bekannt aus Skriptsprachen versucht, wo && und || einen nicht-Bool Werte zurückgeben können:

State s = loadFoobar(&loadPointer, &results); 
s = s || loadBaz(&loadPointer, &results); 
s = s || loadBuz(&loadPointer, &results); 
if(!s) return s; 

aber es gibt ein Problem: Im Gegensatz zu Skriptsprachen, in C++ solche Überlastungen von && und ||lose their short-circuit semantics der macht diesen Versuch sinnlos.

jedoch als dyp wies auf die offensichtliche Sache aus, sobald der s Umfang erhöht, jetzt einfach if wieder eingeführt werden kann.

{ 
    State s; 
    if(!(s = loadFoobar(&loadPointer, &results))) return s; 
    if(!(s = loadBaz(&loadPointer, &results))) return s; 
    if(!(s = loadBuz(&loadPointer, &results))) return s; 
} 
+1

's || (s = loadBaz (..)); 'sollte gut funktionieren: es ist nicht nötig,' || 'zu überladen, wir brauchen nur eine Umwandlung von' State' nach 'bool' (was wir bereits haben). – dyp

+0

@dyp: scheint habe ich das offensichtliche übersehen! Danke! Ich werde es in die Post weben – quetzalcoatl