
Neutrino
Was ist denn hier los?
if(int a = Func1())
{
// Works.
}
if((int a = Func1()))
{
// Fails to compile.
}
if((int a = Func1())
&& (int b = Func2()))
)
{
// Do stuff with a and b.
// This is what I'd really like to be able to do.
}
Abschnitt 6.4.3 des Standards von 2003 erklärt, wie Variablen, die in einer Bedingung einer Auswahlanweisung deklariert sind, einen Gültigkeitsbereich haben, der sich bis zum Ende der Unteranweisungen erstreckt, die von der Bedingung gesteuert werden. Aber ich sehe nicht, wo es etwas darüber aussagt, dass keine Klammern um die Deklaration gesetzt werden können, und es sagt auch nichts über nur eine Deklaration pro Bedingung aus.
Diese Einschränkung ist auch dann störend, wenn nur eine Deklaration in der Bedingung erforderlich ist. Bedenken Sie.
bool a = false, b = true;
if(bool x = a || b)
{
}
Wenn ich den ‘if’-Body-Bereich mit x auf false eingeben möchte, benötigt die Deklaration Klammern (da der Zuweisungsoperator einen niedrigeren Vorrang als das logische OR hat), aber da Klammern nicht verwendet werden können, ist die Deklaration von x außerhalb erforderlich den Körper, wodurch diese Erklärung in einem größeren Umfang als gewünscht preisgegeben wird. Offensichtlich ist dieses Beispiel trivial, aber ein realistischerer Fall wäre einer, in dem a und b Funktionen sind, die Werte zurückgeben, die getestet werden müssen
Ist das, was ich tun möchte, nicht standardkonform, oder sprengt mein Compiler nur meine Eier (VS2008)?

James Johnston
Ich glaube, Sie haben das Problem bereits angedeutet. Was soll der Compiler mit diesem Code machen?
if (!((1 == 0) && (bool a = false))) {
// what is "a" initialized to?
Der “&&”-Operator ist ein kurzgeschlossenes logisches UND. Das heißt, wenn der erste Teil (1==0)
stellt sich als falsch heraus, dann der zweite Teil (bool a = false)
nicht ausgewertet werden, da bereits bekannt ist, dass die endgültige Antwort falsch sein wird. Ob (bool a = false)
nicht ausgewertet wird, was dann später mit dem verwendeten Code zu tun ist a
? Würden wir die Variable einfach nicht initialisieren und undefiniert lassen? Würden wir es auf den Standardwert initialisieren? Was wäre, wenn der Datentyp eine Klasse wäre und dies unerwünschte Nebenwirkungen hätte? Was wäre wenn statt bool
Sie haben eine Klasse verwendet und sie hatte keinen Standardkonstruktor, sodass der Benutzer muss Parameter angeben – was tun wir dann?
Hier ist ein weiteres Beispiel:
class Test {
public:
// note that no default constructor is provided and user MUST
// provide some value for parameter "p"
Test(int p);
}
if (!((1 == 0) && (Test a = Test(5)))) {
// now what do we do?! what is "a" set to?
Scheint, als ob die Einschränkung, die Sie gefunden haben, vollkommen vernünftig erscheint – sie verhindert, dass diese Art von Mehrdeutigkeiten auftreten.
Ab C ++ 17, was Sie versucht haben ist endlich möglich:
if (int a = Func1(), b = Func2(); a && b)
{
// Do stuff with a and b.
}
Beachten Sie die Verwendung von ;
von statt ,
die Erklärung und den tatsächlichen Zustand zu trennen.

Mike Seymour
Der Zustand in einem if
oder while
Aussage kann entweder ein sein Ausdruckoder eine einzelne Variable Erklärung (mit Initialisierung).
Ihr zweites und drittes Beispiel sind weder gültige Ausdrücke noch gültige Deklarationen, da eine Deklaration nicht Teil eines Ausdrucks sein kann. Obwohl es nützlich wäre, Code wie Ihr drittes Beispiel schreiben zu können, würde dies eine erhebliche Änderung der Sprachsyntax erfordern.
Ich sehe nicht, wo etwas darüber steht, dass die Deklaration nicht in Klammern gesetzt werden kann, und es sagt auch nichts darüber aus, dass nur eine Deklaration pro Bedingung vorhanden ist.
Die Syntaxspezifikation in 6.4/1 gibt für die Bedingung Folgendes an:
condition:
expression
type-specifier-seq declarator = assignment-expression
Angabe einer einzigen Deklaration, ohne Klammern oder andere Verzierungen.
Wenn Sie Variablen in einem engeren Geltungsbereich einschließen möchten, können Sie immer zusätzlich verwenden { }
//just use { and }
{
bool a = false, b = true;
if(bool x = a || b)
{
//...
}
}//a and b are out of scope
Der letzte Abschnitt funktioniert bereits, man muss ihn nur etwas anders schreiben:
if (int a = Func1())
{
if (int b = Func2())
{
// do stuff with a and b
}
}

basisch6
Hier ist eine hässliche Problemumgehung mit einer Schleife (wenn beide Variablen Ganzzahlen sind):
#include <iostream>
int func1()
{
return 4;
}
int func2()
{
return 23;
}
int main()
{
for (int a = func1(), b = func2(), i = 0;
i == 0 && a && b; i++)
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
}
return 0;
}
Aber das wird andere Programmierer verwirren und es ist ziemlich schlechter Code, also nicht zu empfehlen.
Eine einfache Umschließung {}
Block (wie bereits empfohlen) ist viel einfacher zu lesen:
{
int a = func1();
int b = func2();
if (a && b)
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
}
}

DukeBrymin
Zu beachten ist auch, dass die Ausdrücke innerhalb des größeren if-Blocks
if (!((1 == 0) && (bool a = false)))
nicht unbedingt von links nach rechts ausgewertet werden. Ein ziemlich subtiler Fehler, den ich damals hatte, hatte mit der Tatsache zu tun, dass der Compiler tatsächlich von rechts nach links statt von links nach rechts testete.
10133900cookie-checkC++, Variablendeklaration im ‘if’-Ausdruckyes
“Wenn ich die Schleife mit betreten möchte” <-- Ihre Beispiele haben
if
.if
ist keine Schleife, sondern eine Bedingung.– crashmstr
20. Oktober 2011 um 13:48 Uhr
@crashmstr: stimmt, aber die Bedingungen für
while
sind die gleichen wie fürif
.– Mike Seymour
20. Oktober 2011 um 14:08 Uhr
Geht das nicht mit dem Komma-Operator? Ich meine:
if (int a = foo(), int b = bar(), a && b)
? Wenn der Kommaoperator nicht überladen ist, sagt der Standard, dass die Ausdrücke von links nach rechts ausgewertet werden und der Ergebniswert der letzte Ausdruck ist. Es funktioniert mitfor
Schleifeninitialisierung, warum nicht hier?– Archie
20. Oktober 2011 um 14:46 Uhr
@Archie: Ich habe es gerade versucht, ich konnte es nicht zum Laufen bringen. Vielleicht kannst du ein funktionierendes Beispiel geben?
– James Johnston
20. Oktober 2011 um 15:10 Uhr
@JamesJohnston: Ich habe es gerade auch versucht, und es scheint nicht zu funktionieren. Diese Idee kam einfach aus meinem Kopf, ich wurde von How vorgeschlagen
if
funktioniert, und es scheint eine falsche Annahme zu sein.– Archie
20. Oktober 2011 um 15:52 Uhr