Could I say that in C++, each statement(without the semicolon) is also an expression?
Also, all expressions, add a semicolon, can become a statement?
Thanks.
No, a C++ statement is not always an expression. For example a for loop is not an expression (of type void). So even with using the comma operator the following is wrong:
/// wrong code, syntactically incorrect in C++
for (int i=0; i<5; i++) {std::cout<<i<<std::endl;}
, // this is a comma operator
x+3
(and you could replace the comma operator by any other operator like +, it is still wrong)
But of course expressions (including assignments and calls) can be used as statements.
Notice that GCC provides, as a language extension, statement exprs (and this extension is accepted by Clang/LLVM); here is a trivial example (the value of the statement expression is given by 2*x):
#include <iostream>
void f (int x) {
// notice the statement-expr starting inside ({ ... })
// the last expression inside the braces gives the value
int y = ({std::cout << "x=" << x << std::endl; 2*x;})+1;
std::cout << "y=" << y << std::endl;
}
With C++11 compilers not accepting that extension, you might create a closure with a lambda-expression and apply it immediately to get an equivalent effect:
void f (int x) {
int y = ([=](){std::cout << "x=" << x << std::endl; return 2*x;})() + 1;
std::cout << "y=" << y << std::endl;
}
Hopefully an optimizing compiler won't bother creating the intermediate closure and produce code equivalent to what GCC could give (with g++ -O2) with the statement expr variant
Some languages, notably Ocaml, Scheme, Haskell, don't have statements or instructions. They have only expressions (and some of them might have some side-effect).
An expression followed by a semicolon is indeed an expression_statement which is a type of statement.
But the converse is not necessarily true: for example consider the jump_statement:
goto foo;
here goto foo is not an expression.
No.
Statements can be composed of any number of things (including expressions), but statements themselves are not expressions.
Have a look at §A.5.
Related
What is the difference between
(type)value
and
type(value)
in C++?
There is no difference; per the standard (§5.2.3):
A simple-type-specifier (7.1.5) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4).
Since the question specified the difference between type(value) and (type)value, there is absolutely no difference.
If and only if you're dealing with a comma-separated list of values can there be a difference. In this case:
If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as an rvalue.
As Troubadour pointed out, there are a certain names of types for which the type(value) version simply won't compile. For example:
char *a = (char *)string;
will compile, but:
char *a = char *(string);
will not. The same type with a different name (e.g., created with a typedef) can work though:
typedef char *char_ptr;
char *a = char_ptr(string);
There is no difference; the C++ standard (1998 and 2003 editions) is clear about this point. Try the following program, make sure you use a compiler that's compliant, such as the free preview at http://comeaucomputing.com/tryitout/.
#include <cstdlib>
#include <string>
int main() {
int('A'); (int) 'A'; // obvious
(std::string) "abc"; // not so obvious
unsigned(a_var) = 3; // see note below
(long const&) a_var; // const or refs, which T(v) can't do
return EXIT_SUCCESS;
}
Note: unsigned(a_var) is different, but does show one way those exact tokens can mean something else. It is declaring a variable named a_var of type unsigned, and isn't a cast at all. (If you're familiar with pointers to functions or arrays, consider how you have to use a parens around p in a type like void (*pf)() or int (*pa)[42].)
(Warnings are produced since these statements don't use the value and in a real program that'd almost certainly be an error, but everything still works. I just didn't have the heart to change it after making everything line up.)
There is no difference when both are casts, but sometimes 'type(value)' is not a cast.
Here's an example from standard draft N3242, section 8.2.1:
struct S
{
S(int);
};
void foo(double a)
{
S w( int(a) ); // function declaration
S y( (int)a ); // object declaration
}
In this case 'int(a)' is not a cast because 'a' is not a value, it is a parameter name surrounded by redundant parentheses. The document states
The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in 6.8 can also occur in the context
of a declaration. In that context, the choice is between a function
declaration with a redundant set of parentheses around a parameter
name and an object declaration with a function-style cast as the
initializer. Just as for the ambiguities mentioned in 6.8, the
resolution is to consider any construct that could possibly be a
declaration a declaration.
In c there is no type (value), while in c/c++ both type (value) and (type) value are allowed.
To illustrate your options in C++ (only one has a safety check)
#include<boost/numeric/conversion/cast.hpp>
using std::cout;
using std::endl;
int main(){
float smallf = 100.1;
cout << (int)smallf << endl; // outputs 100 // c cast
cout << int(smallf) << endl; // outputs 100 // c++ constructor = c cast
cout << static_cast<int>(smallf) << endl; // outputs 100
// cout << static_cast<int&>(smallf) << endl; // not allowed
cout << reinterpret_cast<int&>(smallf) << endl; // outputs 1120416563
cout << boost::numeric_cast<int>(smallf) << endl; // outputs 100
float bigf = 1.23e12;
cout << (int)bigf << endl; // outputs -2147483648
cout << int(bigf) << endl; // outputs -2147483648
cout << static_cast<int>(bigf) << endl; // outputs -2147483648
// cout << static_cast<int&>(bigf) << endl; // not allowed
cout << reinterpret_cast<int&>(bigf) << endl; // outputs 1401893083
cout << boost::numeric_cast<int>(bigf) << endl; // throws bad numeric conversion
}
I'm trying to make a very simple setter method that checks if the start value isn't higher than the end value before setting it.
This is the basic code:
if (start <= this->end) {
this->start = start;
} else {
cerr << "Start cannot be higher than end." << endl;
}
I tried simplifying the method by using an inline if statement like so:
(start <= this->end) ? (this->start = start) : (cerr << "Start cannot be higher than end." << endl);
But IntelliSense tells me the following issue: function "std::basic_ostream<_Elem, _Traits>::basic_ostream(const std::basic_ostream<_Elem, _Traits> &) [with _Elem=char, _Traits=std::char_traits<char>]" cannot be referenced -- it is a deleted function
Uhh, I'm a bit confused as to what "deleted function" has to do with turning a simple if statement into an inline one. Could use some help. Thanks!
A ternary conditional expression a ? b : c is an expression and is therefore not equivalent to if (a) { b } else { c }.
Because it's an expression, it must have a type (and, if that type is not void, it has a value too). This is why you can put a ternary conditional on the right-hand side of an assignment (or even the left-hand side in some cases).
The type of a conditional expression is determined from the types of its second and third operands. If they have the same type, then the result is that type. If there is not some "unambiguous" type that both operand types can be converted to, then the ternary expression does not default to a void results; it instead results in a compilation error.
In your case, the two operands are:
(this->start = start)
(cerr << "Start cannot be higher than end." << endl)
The former has, I assume, some numeric type (the type of this->start) while the latter has std::ostream& type. There is no canonical "common type" of these two types, or in other words, the ternary operator has no "obvious" result type and a compilation error occurs.
An if statement would solve this problem. If you insist on using a conditional operator, you can do so like this:
(start <= this->end)
? void(this->start = start)
: void(cerr << "Start cannot be higher than end." << endl);
Here, both the second and third expressions are cast to void and the entire ternary expression therefore has result type void.
Note that you can't have something like break or return as one of the operands. condition ? void(return foo) : void(return bar) will not work, because return <expr> is a statement, not an expression. It has no type, not even void. In this case, you can only use an if statement. However, you can throw inside a conditional expression since throw <expr> is an expression.
The type of the statement for true case and false case must be matched.
Try this with , this->start (comma operator, then this->start) is added to the false case to match type:
(start <= this->end) ? (this->start = start) : (cerr << "Start cannot be higher than end." << endl, this->start);
By the way, my suggestion is you should simply write if statement in one line instead of using conditional operator like this if you want things in one line:
if (start <= this->end) this->start = start; else cerr << "Start cannot be higher than end." << endl;
I came across this bit of code in an example from the Boost documentation:
std::vector<int> input;
input += 1,2,3,4,5,6,7,8,9;
How cute. Boost has a template for operator+= that takes advantage of the fact that the comma is, under most circumstances, an operator. (Wisely, C++ does not allow a hackist to overload "operator,".)
I like to write cute code too, so I played around some with the comma-operator. I found something that looks weird to me. What do you think the following code will print?
#include <iostream>
int main() {
int i;
i = 1,2;
std::cout << i << ' ';
i = (1,2);
std::cout << i << std::endl;
}
You guessed it. VC++ 2012 prints "1, 2". What's up with that?
[Edit: I should have been more precise. Should have said C++ does not allow operator "," in a list of int's to be overloaded. Or better yet, nothing. The ',' operator can be overloaded for classes and enums.]
CASE 1:
i = 1,2;
= has higher precedence than ,
hence, 1 is assigned to i.
Since assignment evaluates to an lvalue in c++,(evaluates to rvalue in c) it becomes i,2 which evaluates to2 (refer NOTE)
CASE 2:
i = (1,2);
() has higher precedence than =
expressions or operands separated by , operator evaluates to the value of the last expression or operand hence, 2 is assigned to i
NOTE
a comma expression like 33,77,x,y,z is evaluated from left to right.
The result of such comma expression is the value of rightmost expression .
Examples
Consider, int z=100;
then
1,4,5; //evaluates to 5
1,100,z+100; //evaluates to 200
Simple: "=" has higher precendence.
i = 1,2;
Is like (i=1),2, meaning the result of the expression is 2 but it's discarded.
i = (1,2);
The result of (1,2) is 2.
EDIT: this might be so things like
for (i=0, j=0; ...)
work as expected.
(I don't have a serious need for this answer, I am just inquisitive.)
Can every if-else construct be replaced by an equivalent conditional expression using the conditional operator ?:?
Does every if-else constructs can be replaced by an equivalent conditional expression using conditional operator?
No, you've asked this backwards. The "bodies" of if/else contain statements, and it is not possible to turn every statement into an expression, such as try, while, break statements, as well as declarations. Many "statements" are really expressions in disguise, however:
++i;
blah = 42;
some_method(a,b,c);
All of these are statements which consist of one expression (increment, assignment, function-call, respectively) and could be turned into expressions within a conditional.
So, let's reverse the question, since it sounds like you really want to know how equivalent if/else statements are to ternary conditional expressions: Can every conditional expression be replaced by equivalent if/else statements? Almost all, yes. A common example is return statements:
return cond ? t : f;
// becomes:
if (cond) return t;
else return f;
But also other expressions:
n = (cond ? t : f);
// becomes:
if (cond) n = t;
else n = f;
Which starts to point to where conditional expressions cannot be easily replaced: initializations. Since you can only initialize an object once, you must break up an initialization that uses a conditional into using an explicit temporary variable instead:
T obj (cond ? t : f);
// becomes:
SomeType temp;
if (cond) temp = t;
else temp = f;
T obj (temp);
Notice this is much more tedious/cumbersome, and requires something type-dependent if SomeType cannot be default-constructed and assigned.
On the surface of it, no. The conditional operator is an expression (that is, it has a value), while if/else is a statement (thus has no value). They fulfill different "needs" within the language syntax.
However, since you can ignore expression values, and since any expression can be turned into a statement by adding a semicolon, you can essentially emulate if/else with a conditional expression and two auxiliary functions:
// Original code:
if (condition) {
// block 1
}
else {
// block 2
}
// conditional expression replacement:
bool if_block() {
// block 1
return true;
}
bool else_block() {
// block 2
return true;
}
// Here's the conditional expression. bool value discarded:
condition ? if_block() : else_block();
However, having said that, I'm not sure it's anything more than a curiosity...
No, of course not. For reasons already mentioned, and more!
#include <cstdlib>
#include <iostream>
int main()
{
if(int i = std::rand() % 2)
{
std::cout << i << " is odd" << std::endl;
}
else
{
std::cout << i << " is even" << std::endl;
}
}
Check out where is is declared. It's not an often used technique, but it can be used in situations like COM where every call returns HRESULT which is (almost always) zero on success (S_OK), non-zero on failure, so you might write something like:
if(HRESULT hr = myInterface->myMethod())
{
_com_raise_error(hr);
}
The ternary operator can't do anything analogous.
if( cond )
break;
else
a=b;
can not always be replaced by ?: operator. You can often (if not always) rethink your whole code to provide for this substitute, but generally you can't put anything that controls execution into ?:. break, return, loops, throw, etc.
In principle, yes:
if (A) B; else C
becomes
try {
A ? throw TrueResult() : throw FalseResult();
// or: throw A ? TrueResult() : FalseResult();
} catch (TrueResult) {
B;
} catch (FalseResult) {
C;
}
Compared to using procedures (which are more natural), this allows break, continue, return etc. It requires evaluation of A doesn't end with TrueResult/FalseResult but if you use those exceptions only to simulate if, it won't be a problem.
Using the conditional operator results in an expression and both potential results of the conditional operator must be 'compatible' (convertible to the same type).
An if-else construct need not even 'return' any type much less the same one from both branches.
The conditional operator expects to have both of the items following the ? be rvalues (since the result of a conditional operator is itself an rvalue) - so while I'm not entirely an expert on the C/C++ standards, my intuition would be that the following would be disallowed (or failing that, extremely poor coding style...):
(condition) ? return x : return y;
whereas the if-else version would be quite standard:
if(condition) return x;
else return y;
Now, that said, could you take any program and write a similarly functioning program that didn't use if-else? Sure, you probably could. Doesn't mean it would be a good idea, though. ;)
GCC has statement expression, using it you can rewrite if statements to equivalent ?: expressions:
if (<expression>)
<statement1>
else
<statement2>
EDIT: The void casts serves two purpose. The subexpressions in ?: must have the same type, and without the void cast the compiler may print warning: statement with no effect.
(<expression>)? (void)({<statement1>}) : (void)({<statement2>});
I'm a TA for an intro C++ class. The following question was asked on a test last week:
What is the output from the following program:
int myFunc(int &x) {
int temp = x * x * x;
x += 1;
return temp;
}
int main() {
int x = 2;
cout << myFunc(x) << endl << myFunc(x) << endl << myFunc(x) << endl;
}
The answer, to me and all my colleagues, is obviously:
8
27
64
But now several students have pointed out that when they run this in certain environments they actually get the opposite:
64
27
8
When I run it in my linux environment using gcc I get what I would expect. Using MinGW on my Windows machine I get what they're talking about.
It seems to be evaluating the last call to myFunc first, then the second call and then the first, then once it has all the results it outputs them in the normal order, starting with the first. But because the calls were made out of order the numbers are opposite.
It seems to me to be a compiler optimization, choosing to evaluate the function calls in the opposite order, but I don't really know why. My question is: are my assumptions correct? Is that what's going on in the background? Or is there something totally different? Also, I don't really understand why there would be a benefit to evaluating the functions backwards and then evaluating output forward. Output would have to be forward because of the way ostream works, but it seems like evaluation of the functions should be forward as well.
Thanks for your help!
The C++ standard does not define what order the subexpressions of a full expression are evaluated, except for certain operators which introduce an order (the comma operator, ternary operator, short-circuiting logical operators), and the fact that the expressions which make up the arguments/operands of a function/operator are all evaluated before the function/operator itself.
GCC is not obliged to explain to you (or me) why it wants to order them as it does. It might be a performance optimisation, it might be because the compiler code came out a few lines shorter and simpler that way, it might be because one of the mingw coders personally hates you, and wants to ensure that if you make assumptions that aren't guaranteed by the standard, your code goes wrong. Welcome to the world of open standards :-)
Edit to add: litb makes a point below about (un)defined behavior. The standard says that if you modify a variable multiple times in an expression, and if there exists a valid order of evaluation for that expression, such that the variable is modified multiple times without a sequence point in between, then the expression has undefined behavior. That doesn't apply here, because the variable is modified in the call to the function, and there's a sequence point at the start of any function call (even if the compiler inlines it). However, if you'd manually inlined the code:
std::cout << pow(x++,3) << endl << pow(x++,3) << endl << pow(x++,3) << endl;
Then that would be undefined behavior. In this code, it is valid for the compiler to evaluate all three "x++" subexpressions, then the three calls to pow, then start on the various calls to operator<<. Because this order is valid and has no sequence points separating the modification of x, the results are completely undefined. In your code snippet, only the order of execution is unspecified.
Exactly why does this have unspecified behaviour.
When I first looked at this example I felt that the behaviour was well defined because this expression is actually short hand for a set of function calls.
Consider this more basic example:
cout << f1() << f2();
This is expanded to a sequence of function calls, where the kind of calls depend on the operators being members or non-members:
// Option 1: Both are members
cout.operator<<(f1 ()).operator<< (f2 ());
// Option 2: Both are non members
operator<< ( operator<<(cout, f1 ()), f2 () );
// Option 3: First is a member, second non-member
operator<< ( cout.operator<<(f1 ()), f2 () );
// Option 4: First is a non-member, second is a member
cout.operator<<(f1 ()).operator<< (f2 ());
At the lowest level these will generate almost identical code so I will refer only to the first option from now.
There is a guarantee in the standard that the compiler must evaluate the arguments to each function call before the body of the function is entered. In this case, cout.operator<<(f1()) must be evaluated before operator<<(f2()) is, since the result of cout.operator<<(f1()) is required to call the other operator.
The unspecified behaviour kicks in because although the calls to the operators must be ordered there is no such requirement on their arguments. Therefore, the resulting order can be one of:
f2()
f1()
cout.operator<<(f1())
cout.operator<<(f1()).operator<<(f2());
Or:
f1()
f2()
cout.operator<<(f1())
cout.operator<<(f1()).operator<<(f2());
Or finally:
f1()
cout.operator<<(f1())
f2()
cout.operator<<(f1()).operator<<(f2());
The order in which function call parameters is evaluated is unspecified. In short, you shouldn't use arguments that have side-effects that affect the meaning and result of the statement.
Yeah, the order of evaluation of functional arguments is "Unspecified" according to the Standards.
Hence the outputs differ on different platforms
As has already been stated, you've wandered into the haunted forest of undefined behavior. To get what is expected every time you can either remove the side effects:
int myFunc(int &x) {
int temp = x * x * x;
return temp;
}
int main() {
int x = 2;
cout << myFunc(x) << endl << myFunc(x+1) << endl << myFunc(x+2) << endl;
//Note that you can't use the increment operator (++) here. It has
//side-effects so it will have the same problem
}
or break the function calls up into separate statements:
int myFunc(int &x) {
int temp = x * x * x;
x += 1;
return temp;
}
int main() {
int x = 2;
cout << myFunc(x) << endl;
cout << myFunc(x) << endl;
cout << myFunc(x) << endl;
}
The second version is probably better for a test, since it forces them to consider the side effects.
And this is why, every time you write a function with a side-effect, God kills a kitten!