Test for learners

S

Stefan Ram

I have devised two tests for learners of C++:

1.) When you want to test whether something is an
expression within a correct program, put a pair of
parentheses around it. If it is an expression, the
program will still be correct and the behavior of the
program will not change.

2.) When you want to test whether something is a statement
within a correct program, put a pair of braces around it.
If it is a statement, the program will still be correct
and the behavior of the program will not change.

To make sure that the rules are correct, I would like to know
whether anyone can find a counterexample. (I am aware of such
a counterexample in Java, but not in C++.)
 
J

Juha Nieminen

Stefan said:
2.) When you want to test whether something is a statement
within a correct program, put a pair of braces around it.
If it is a statement, the program will still be correct
and the behavior of the program will not change.

int i = 5; // Is this a statement?
std::cout << i << "\n";

Let's test:

{ int i = 5; }
std::cout << i << "\n";

I suppose it isn't. Then what is it?
 
S

Stefan Ram

Juha Nieminen said:
int i = 5; // Is this a statement?

Yes.

My rule has failed.

So, enclosing a statement in braces can change the correctness
and/or behavior.

It might still be valid that a program that complies with the
BNF grammar of C++ will still comply with this grammar when a
statement is enclosed in an additional pair of braces.
(But it might be erroneous after the modification for reasons
of scoping.)

One also might still ask whether it holds that if enclosing a
source text in an additional pair of braces does not change
the behavior, then that source text is a statement.

But, no, here is a counterexample for this:

int main(){ int a[ 2 ][ 2 ]={ 0 }; }
int main(){ int a[ 2 ][ 2 ]={{ 0 }}; }

So this test only is an indication that something is a
statement, but not a strict evidence.
 
A

Andrey Tarasevich

Stefan said:
I have devised two tests for learners of C++:

1.) When you want to test whether something is an
expression within a correct program, put a pair of
parentheses around it. If it is an expression, the
program will still be correct and the behavior of the
program will not change.

Hm... I'm not sure about the intended scope of this rule. Say in this
declaration

int i;

I can put a pair of parentheses around 'i'

int (i);

and get an equivalent program. This still doesn't mean that this
specific 'i' in this specific context is an expression. It is not. Sure,
out of context 'i' is a valid expression, but in the above context it is
a declarator.

BTW, is your rule supposed to work both ways? I.e. if one can't put the
braces around it, does that mean it is not an expression? If so, then it
is not true as well. For example, in this context

struct A { int i; };

struct B : A {
void foo() {
int A::*p = &A::i; // 'A::i' is an expression in this context
}
};

'A::i' is an expression. However, if I put braces around it as in

struct B : A {
void foo() {
int A::*p = &(A::i); // ERROR
}
};

the program becomes ill-formed.
2.) When you want to test whether something is a statement
within a correct program, put a pair of braces around it.
If it is a statement, the program will still be correct
and the behavior of the program will not change.

In C++ (as opposed to C, for example) declarations form declaration
_statements_. Juha already gave you an counterexample where extra braces
break the code.
 
A

Andrey Tarasevich

Andrey said:
...
BTW, is your rule supposed to work both ways? I.e. if one can't put the
braces around it, does that mean it is not an expression? If so, then it
is not true as well. For example, in this context

struct A { int i; };

struct B : A {
void foo() {
int A::*p = &A::i; // 'A::i' is an expression in this context
}
};

'A::i' is an expression. However, if I put braces around it as in

struct B : A {
void foo() {
int A::*p = &(A::i); // ERROR
}
};

the program becomes ill-formed.
...

.... although a pedantic person might argue that while 'A::i' is indeed a
valid expression in 'B::foo', nevertheless 'A::i' in '&A::i' is _not_ a
sub-expression, but rather a mere 'qualified-id'. There would probably
be no reason to even consider this pedantic issue, if not for your rule :)
 
S

Stefan Ram

Andrey Tarasevich said:
BTW, is your rule supposed to work both ways? I.e. if one can't
put the braces around it, does that mean it is not an expression?

I was not sure about this, too.

Now, I see, that these rules are not valid always, so I will
have to use wording like »often« for these rules.

BTW: I believe, a qualified-id is an expression, too, because
it is an id-expression, whis is a primary-expression.
 
D

Default User

Stefan said:
I was not sure about this, too.

Now, I see, that these rules are not valid always, so I will
have to use wording like »often« for these rules.

Frankly, I'd drop them altogether. Even if they were 100% reliable, I
don't think they are useful to a student. As they aren't even
consistently true, their utility is further dimished.



Brian
 
M

Martin Eisenberg

Stefan said:
1.) When you want to test whether something is an
expression within a correct program, put a pair of
parentheses around it. If it is an expression, the
program will still be correct and the behavior of the
program will not change.

Putting parentheses around the function name in an unqualified call
disables ADL; to wit--

#include <iostream>

using namespace std;

namespace N {
struct S {};
void f(S) { cout << "N::f()"; };
}

int main()
{
N::S s;
f(s); // compiles
// (f)(s); // doesn't compile
return 0;
}


Martin
 
J

James Kanze

Putting parentheses around the function name in an unqualified
call disables ADL;

Putting parentheses around the name of a function-style macro
can unmask a real function which it hid. So without parenthese,
you get a macro, with them, you don't. And we all know that
macros can wreck havoc and change the semantics in all sorts of
ways.
 
J

Jerry Coffin

[ ... ]
I did look up the expression syntax earlier, but now, it's late evening.

Yes -- one of the possibilities for a primary expression is an id-
expression, which is either a qualified id or an unqualified id. An
identifier is an unqualified id (section 5.1).
 
J

James Kanze

* James Kanze:
I couldn't think of anything when I saw the original article.

I didn't even try:). But when putting parentheses around a
function was mentionned, it reminded me of the C days (without
inline), when the trick was used to allow an implementation to
make isspace() a macro, but still allow you to take the address
of the function: isspace is a function style macro, which will
only be recognized as a macro and expanded as such if it is
immediately followed by a '(' token: "isspace,", for example,
doesn't expand the macro, so the code "sees" the external
function declaration which preceded the macro definition. And
of course, as soon as "macro" came to mind, I realized that it
was anythinig goes.
And I'm still not sure you guys are right.
Is an unparenthesized function name that's part of a function
call, really an expression? A function name on its own is an
expression, and a complete function call is, but the
unparenthesized function name in a call?

Of course. Otherwise, how could you construct a function call
expression? (Remember, () is an operator, just like any other
operator. It can even be overloaded. And if it's not
overloaded, it's left hand argument can be any expression which
has function or pointer to function type.)
 
S

Stefan Ram

James Kanze said:
Of course. Otherwise, how could you construct a function call
expression?

By a modification of the grammar and the language.
For example, in Java, the method name is /never/ an
expression and cannot be written inside of parentheses.
 
J

James Kanze

By a modification of the grammar and the language.
For example, in Java, the method name is /never/ an
expression and cannot be written inside of parentheses.

And there are no pointers to functions, or even free functions.
Java's not C++.
 
A

Andrey Tarasevich

Alf said:
And I'm still not sure you guys are right.

Is an unparenthesized function name that's part of a function call,
really an expression?
Yes.

A function name on its own is an expression, and a
complete function call is, but the unparenthesized function name in a call?

Yes, it is an expression. With an ordinary function it is pretty
obvious, since you can always use the function name alone as a valid
(albeit useless) expression

void foo();

foo; // <- a valid expression

With member functions things are a bit more complicated. One can't use a
qualified name of a member function as a standalone expression

struct S { void foo(); };

S::foo; // <- ill-formed

which often leads people to conclude that a member function name alone
is not an expression. In reality, from the language point of view, it is
an expression, but it is only allowed to be used in a restricted set of
contexts, as described in 5/10.
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top