The question is simple. Why does this compile:
bool b(true); if (b) { /* */ }
And this compile:
if (bool b = true) { /* */ }
But not this:
if (bool b(true)) { /* */ }
In my real code, I need to construct an object and test it, while also having it destroyed when the if-block ends. Basically, I'm looking for something like this:
{ Dingus dingus(another_dingus); if (dingus) { // ... } }
Of course, this would work:
if (Dingus dingus = another_dingus) { /* */ }
But then I'm constructing a Dingus
and calling operator=
on it. It seems logical to me that I would be able to construct the object using whatever constructor I please.
But I'm baffled why this isn't grammatically correct. I've tested with G++ and MSVC++ and they both complain about this construct, so I'm sure it's part of the spec but I'm curious as to the reasoning for this and what non-ugly workarounds there may be.
If you're new to the syntax that's used in the code sample, if (int i = 5) { is a perfectly valid way of declaring and defining a variable, then using it inside the given if statement.
The variable can be declared, but it cannot be initialized.
Java allows you to declare variables within the body of a while or if statement, but it's important to remember the following: A variable is available only from its declaration down to the end of the braces in which it is declared. This region of the program text where the variable is valid is called its scope .
You can still declare variables in switch statements, you just have to put curly brackets around the code after the case label.
It's a bit technical. There's no reason why what you want couldn't be allowed, it just isn't. It's the grammar.
An if
statement is a selection statement, and it takes the grammatical form:
if (condition) statement
Here, condition
can be either:
expression
ortype-specifier-seq declarator = assignment-expression
And there you have it. Allowing a declaration in a condition is a special case, and it must follow that form or your program is ill-formed. They could have probably allow direct-initialization instead of copy-initialization, but there isn't really any motivation to do so now. As Johannes Schaub points out, this change would break existing code, so it's pretty much never going to happen.
Let_Me_Be notes that C++11 added a third form (I'm ignoring attributes here):
decl-specifier-seq declarator braced-init-list
So if (bool b{true})
is fine. (This can't possibly break any valid existing code.)
Note your question seems to do with efficiency: don't worry. The compiler will elide the temporary value and just construct the left-hand side directly. This, however, requires your type be copyable (or movable in C++11).
It should be noted.that if(functor(f)(123)) ...;
would then not be the call of an anonymous functor with argument 123 anymore but would declare a functor initialized by 123.
And i think introducing such pitfalls for that little feature is not worth it.
Since it may not be clear what the above means, let's take a deeper look. First remember that parentheses around a declarator are allowed, including for the degenerate case of being directly around a declared name:
int(n) = 0; // same: int n = 0; int(n)(0); // same: int n(0);
Both of the parenthesized versions are ambiguous, because the first could be an assignment and the second could be a function call. But both could also be declarations. And the Standard says that they are declarations.
If we will allow paren-initializers in conditions, then we introduce the latter ambiguity into conditions too, just as for the statement case. Thus we would make valid condition expressions that are used nowadays into declarations after the feature is supported. Consider
typedef bool(*handler_type)(int); bool f(int) { /* ... */ } bool f(int, int) { /* ... */ } void call_it() { // user wants to call f(int), but it is overloaded! // -> user tries a cast... if(handler_type(f)(0)) { /* ... */ } }
What you think will happen? Of course, it will never enter the if
body, because it always declares a null pointer. It never calls function f
. Without the "feature" it will properly call f
, because we don't have the ambiguity. This is not limited to only (f)
, but also (*f)
(declares a pointer), (&f)
(declares a reference) et al.
Again: Do we want such pitfalls as price for such a small feature? I don't know how many people even know they could declare stuff in a condition.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With