Difference between declaring a variable in a for() and an if() statement

J

Juha Nieminen

This is more a theoretical question, so please skip on nitpicking on
whether it "makes sense".

Suppose that I have a class named eg. Counter which constructor takes
an integer as parameter. I can do things like this without problems:

for(Counter c = 5; ...)

for(Counter c(5); ...)

if(Counter c = 5) ...

However, this will produce a compiler error, at least with gcc:

if(Counter c(5)) ...

The error message I'm getting is: "error: expected primary-expression
before 'c'"

There is a definite difference between "Counter c = 5" and
"Counter c(5)": The former requires for the copy constructor to be
accessible. If it isn't, then the former syntax cannot be used.

In that case Counter instances can be created with the for() statement
by using "for(Counter c(5); ...)". However, I can't think of a way of
doing the same with the if() statement.

Why is there such a difference? Would it be possible to create such
instances within an if() statement?

One could think that creating an object inside the condition of an
if() statement makes absolutely no sense, but there might be situations
where it could make at least some sense, for example:

if(InputStream iStream("file.txt")) doSomethingWith(iStream);
else log("Could not open file.txt");

Note that the above works fine if InputStream is copyable, by using
the other syntax, ie:

if(InputStream iStream = "file.txt") doSomethingWith(iStream);
else log("Could not open file.txt");

However, if it's not copyable, then I don't know how it could be done.
(And no, I'm not asking about alternative ways of doing the same thing.
I know C++ well enough to figure out on my own. It's not what I'm asking.)
 
A

Alf P. Steinbach

* Juha Nieminen:
This is more a theoretical question, so please skip on nitpicking on
whether it "makes sense".

Suppose that I have a class named eg. Counter which constructor takes
an integer as parameter. I can do things like this without problems:

for(Counter c = 5; ...)

for(Counter c(5); ...)

if(Counter c = 5) ...

However, this will produce a compiler error, at least with gcc:

if(Counter c(5)) ...

The error message I'm getting is: "error: expected primary-expression
before 'c'"

There is a definite difference between "Counter c = 5" and
"Counter c(5)": The former requires for the copy constructor to be
accessible. If it isn't, then the former syntax cannot be used.

In that case Counter instances can be created with the for() statement
by using "for(Counter c(5); ...)". However, I can't think of a way of
doing the same with the if() statement.

Why is there such a difference?

Syntactically because in the 'if' you're using a 'condition'. Which is
special-cased to allow a simple declaration of the "=" form. You can use this
also as the second part of a 'for' head, because that's also a 'condition'.

The first part of a 'for' head allows a general (simple) declaration.

But as to why the syntax is as it is, I think it's just a symptom of the C and
C++ syntax not being sufficiently abstract, but instead having special cases
everywhere, trying to produce a /semblance/ of a suitably abstracted syntax
(e.g., this concerns semicolons: the syntax lacks a notion of "command").

Would it be possible to create such
instances within an if() statement?

You can always enclose the 'if' statement in a block, like

// blah blah
{
Counter c(5);
if( c ) { ... }
}

That's a main part of what blocks are for, namely, introducing limited scopes.

One could think that creating an object inside the condition of an
if() statement makes absolutely no sense, but there might be situations
where it could make at least some sense, for example:

if(InputStream iStream("file.txt")) doSomethingWith(iStream);
else log("Could not open file.txt");

Note that the above works fine if InputStream is copyable, by using
the other syntax, ie:

if(InputStream iStream = "file.txt") doSomethingWith(iStream);
else log("Could not open file.txt");

However, if it's not copyable, then I don't know how it could be done.
(And no, I'm not asking about alternative ways of doing the same thing.
I know C++ well enough to figure out on my own. It's not what I'm asking.)

Oh. Sorry.


Cheers & hth.,

- Alf
 
M

Marcel Müller

Juha said:
Suppose that I have a class named eg. Counter which constructor takes
an integer as parameter. I can do things like this without problems:

for(Counter c = 5; ...)

for(Counter c(5); ...)

if(Counter c = 5) ...

However, this will produce a compiler error, at least with gcc:

if(Counter c(5)) ...

The error message I'm getting is: "error: expected primary-expression
before 'c'"

if expects a boolean expression. Nothing else.

For is in fact like a macro, replacing

for (INIT; COND; INC)
{ BODY }

by

{ INIT;
if (COND)
{ BODY;
while (true)
{ INC;
if (!(COND))
break;
BODY;
}
}
}

That's why you can define locals in the INIT part.

Note that earlier C++ version did not have the outer brace. This caused
the definitions in INIT to be in the scope of the enclosing block.


Marcel
 
A

Alf P. Steinbach

* Marcel Müller:
if expects a boolean expression. Nothing else.

That's wrong.

As you would have discovered by reading the only previous response before
posting yourself.

It's often a good idea to read before posting.


For is in fact like a macro, replacing

for (INIT; COND; INC)
{ BODY }

by

{ INIT;
if (COND)
{ BODY;
while (true)
{ INC;
if (!(COND))
break;
BODY;
}
}
}

That's why you can define locals in the INIT part.

Well, sort of (e.g., the syntax doesn't require a block as body). But the idea
of understanding the loop in terms of an equivalent is sound: also the holy
standard defines the semantics of the 'for' loop in terms of an, except for the
effect of 'continue', equivalent 'while' construct. And it's much simpler than
the above: can you figure it out?


Cheers & hth.,

- Alf
 
J

Juha Nieminen

Marcel said:
if expects a boolean expression. Nothing else.

Not true. This works just fine: if(int i = 5) ...
The same is true if instead of "int" you use a class (which is
copy-constructible and takes an integer (or whatever you want to write
there) as constructor parameter).
 
J

James Kanze

This is more a theoretical question, so please skip on nitpicking on
whether it "makes sense".
Suppose that I have a class named eg. Counter which constructor takes
an integer as parameter. I can do things like this without problems:
for(Counter c = 5; ...)
for(Counter c(5); ...)
if(Counter c = 5) ...
However, this will produce a compiler error, at least with gcc:
if(Counter c(5)) ...
The error message I'm getting is: "error: expected primary-expression
before 'c'"
There is a definite difference between "Counter c = 5" and
"Counter c(5)": The former requires for the copy constructor to be
accessible. If it isn't, then the former syntax cannot be used.
In that case Counter instances can be created with the for() statement
by using "for(Counter c(5); ...)". However, I can't think of a way of
doing the same with the if() statement.
Why is there such a difference? Would it be possible to create such
instances within an if() statement?

Try:
for ( ... ; Counter c(5) ; ... )

It's the second element in the for which is a condition (and
thus which corresponds to the condition in an if or a while).
One could think that creating an object inside the condition of an
if() statement makes absolutely no sense, but there might be situations
where it could make at least some sense, for example:
if(InputStream iStream("file.txt")) doSomethingWith(iStream);
else log("Could not open file.txt");

What's wrong with:

InputStream iStream( "file.txt" ) ;
if ( iStream ) {
doSomethingWith( iStream ) ;
} else {
log( "Could not open file.txt" ) ;
}

It has the advantage of actually being readable.

(I've yet to find any case where declaring a variable in a
condition makes sense. The ability to do so is a misfeature of
C++.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top