Node is a very simple class with a just a constructor and a few variables: a "name" (actually just a char) and two child Node pointers called "left" and "right".
I was just starting to write some code that needs to drop to the left-most node, and I was quite pleased when I came up with this:
Node *current = this->root;
while (true) (current->left != nullptr) ? current = current->left : break;
Seems simple enough: in an infinite loop, check to see if current has a left child, if so, set current to that left child, if not, break out of the loop. It's a cool little one-liner, not too unreadable. (And I commented it!)
Well, my compiler doesn't like it:
iterator.cpp:20:70: error: expected expression
while (true) (current->left != nullptr) ? current = current->left : break;
^
1 error generated.
Also, just throwing some braces into the while loop and moving the ternary operator to it's own line didn't help (unsurprisingly). I had to turn it into an if/else for the compiler to accept it.
Can someone explain how it's interpreting the one-liner and why it objects?
The ternary conditional operator is an operator that combines multiple expressions into a larger expression. break is a statement and not an expression, so it can't be used inside a ternary conditional expression.
You could, though, rewrite your code like this:
while (current->left != nullptr) current = current->left;
Hope this helps!
Why can't I use a “break” statement inside a ternary conditional statement in C++?
Because the ternary operator isn't a statement at all, it's an operator, and it is composed of expressions, not statements. break is a statement, not an expression.
Related
I'm making a binary tree and this is my insert function; it works perfectly:
if(newData < data){
if(left) left->insert(newData);
else left = new Node(newData);
}else{
if(right) right->insert(newData);
else right = new Node(newData);
}
I wanted to transform this into this:
if(newData < data)
left ? left->insert(newData) : left = new Node(newData);
else
right = right ? right : new Node(newData);
However, I'm getting this error:
Left operand to ? is void, but right operand is of type 'Node *'
I understand this is because there's something to do with having the ternary statement be the same on both sides, but I was wondering if anyone knew a possible solution for this short of just using an if/else statement so I can learn the limitations behind the code.
Thanks!
The ternary operator is an expression.
It is not an if else statement.
It returns a result - at runtime, so its type has to be determined during compilation.
It can only be one type at a time, so in effect both branches have to return a result of the same type
In your branches, the types of the expressions are different. This is the reason of the error.
The ternary operator ? is not just a shorthand for if, but requires three expressions:
condition ? exprIfTrue : exprIfFalse
If the condition evaluates to true, the whole constuct evaluates to exprIfTrue, if false to exprIfFalse. In contrast to if it can be used in an assignment, hence the two expressions have to have a type that conforms to the variable the result is assigned to. ? can better be compared to the if in functional languages.
Thanks to everyone that helped so incredibly quickly! To all of you who mentioned the readability of the new code as opposed to the original, I totally understand that I should keep it as it is in the beginning. Thanks to everyone posting about the nature of the statement!
For anyone ends up wondering what the solution was, for fun, Eljay nailed it:
((newData < data) ? left : right) =
(newData < data) ? (left ? (( void )left->insert(newData), left)
: new Node(newData))
: (right ? (( void )right->insert(newData), right)
: new Node(newData));
Thank you all so much! I'm extremely impressed by how awesome the StackOverflow community is!
Let us say I have an integer array representing the chess pieces on a board;
int board[8][8];
In my chess game, I am currently coding a generator function that will return an integer vector of all legal moves.
Naturally, I will be using if statements
I am at a point where I need to check a certain element in the board relative to a piece on the board
For example, If I have a pawn piece;
board[row][col] == 'p';
I need to generate [row+1][col], [row+2][col] and in some cases if it can attack a piece, a change in column too.
But if a piece is on any edge of the board, board[row+1][col] will return be index out of range
For that reason I need an extra if statement.
My question is, shall i use:
if (pieceisnotonedge && board[row+1][col] == 0)
or
if (pieceisnotonedge)
{
if (board[row+1][col] == 0)
}
For the first example, if pieceisnotonedge returns false, will it also check the next condition? Because if it does, then I am in trouble.
For the first example, if pieceisnotonedge returns false, will it also
check the next condition?
No, it will not. Because the build-in logical operators do short-circuiting. From cppreference.com:
Builtin operators && and || perform short-circuit evaluation (do not
evaluate the second operand if the result is known after evaluating
the first), but overloaded operators behave like a regular function
calls and always evaluate both operands
Therefore, in
if (pieceisnotonedge && board[row+1][col] == 0)
if the pieceisnotonedge is false, the second will not be evaluated. Therefore, having a nested ifs is redundant, and you can go with the first version.
For the first example, if pieceisnotonedge returns false, will it also check the next condition?
No. It will "short-circuit" because if the first condition is false, checking the conditions after it is unnecessary. Read more here and here.
This is guranteed by the C++ standard:
7.6.14
... && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.
Note that, for || this is opposite, that is, if the first condition is "true", then checking the conditions afterwards is unnecessary
Shall i use; or...
Both are same, if you have a short if statement (with only two conditions), I would suggest using the first approach. In terms of efficiency there is no difference and you can verify this by looking at the generated assembly for both cases on godbolt
For the shown code there is no difference, both board[row+1][col] == 0 are only evaluated if pieceisnotonedge is true.
If you should use one or the other, cannot be said be in general, as it depends on other factors (like semantic, readability, …) too.
If you e.g. want to have an action that it done if either pieceisnotonedge or board[row+1][col] == 0 is false, then you probably would use &&, because then you can write:
if (pieceisnotonedge && board[row+1][col] == 0) {
} else {
// do something else
}
with your other style you would need to write:
if (pieceisnotonedge){
if (board[row+1][col] == 0) {
// do something else
}
} else {
// do something else
}
In general, your first aim should be to have readable code. While pieceisnotonedge && board[row+1][col] == 0 easy to read, more complex expressions might not be. So you would decide that on a case by case basis, if you want to use one expression or multiple if.
For the first example, if pieceisnotonedge returns false, will it also check the next condition?
No. It will stop immediately after pieceisnotonedge is evaluated to false. There is no subsequent check for the remainder condition board[row+1][col] == 0
You can use nested if as the second code as well - no difference. It's just a matter of what code would look clearer.
Node is a very simple class with a just a constructor and a few variables: a "name" (actually just a char) and two child Node pointers called "left" and "right".
I was just starting to write some code that needs to drop to the left-most node, and I was quite pleased when I came up with this:
Node *current = this->root;
while (true) (current->left != nullptr) ? current = current->left : break;
Seems simple enough: in an infinite loop, check to see if current has a left child, if so, set current to that left child, if not, break out of the loop. It's a cool little one-liner, not too unreadable. (And I commented it!)
Well, my compiler doesn't like it:
iterator.cpp:20:70: error: expected expression
while (true) (current->left != nullptr) ? current = current->left : break;
^
1 error generated.
Also, just throwing some braces into the while loop and moving the ternary operator to it's own line didn't help (unsurprisingly). I had to turn it into an if/else for the compiler to accept it.
Can someone explain how it's interpreting the one-liner and why it objects?
The ternary conditional operator is an operator that combines multiple expressions into a larger expression. break is a statement and not an expression, so it can't be used inside a ternary conditional expression.
You could, though, rewrite your code like this:
while (current->left != nullptr) current = current->left;
Hope this helps!
Why can't I use a “break” statement inside a ternary conditional statement in C++?
Because the ternary operator isn't a statement at all, it's an operator, and it is composed of expressions, not statements. break is a statement, not an expression.
I stumbled across an interesting case that makes me question what I know about if statements.
I have this code for insertion for binary trees:
void insert(Node<T>* ¤tNode, const T& x)
{
if (currentNode == nullptr)
{
currentNode = new Node<T>(x);
}
if (x >= binTree<T>::root->data)
{
insert(currentNode->right, x);
}
else if (x < binTree<T>::root->data)
{
insert(currentNode->left, x);
}
}
The problem I was facing was that whenever I called this function to insert into the tree, it gave me a segmentation fault, after running valgrind, it told me that a stack overflow error occurred. I tested to see if the first if block was causing the problem by writing a cout statement and lo and behold my cout statement was excuted infinitely many times.
However, after changing that second if block to one single unified if statement like this:
if {}
else if {}
else if {}
The code worked perfectly and was not stuck in an infinite loop. How does one explain this behavior? Doesn't the if statement just test the condition and if it is false it continues on the rest of the block?
It should be quite obvious.
Without the else, each call to insert always makes at least one more call to insert, leading to an infinite number of calls. The second if is always executed, and either way it calls insert.
With the else, it is possible for insert not to call insert -- if currentNode is null.
Not expecting any credit for this answer since it's coming in late, but wanted to add another perspective. The problem here is that you've created (intentionally or not) a recursive function without a base case (which equals stack overflow).
It's guaranteed that one of the following statements will be true:
if (x >= binTree<T>::root->data)
{
insert(currentNode->right, x);
}
else if (x < binTree<T>::root->data) //could just as well have been only "else"
{
insert(currentNode->left, x);
}
By implementing the solution you found and which #David Schwartz confirmed, you're essentially converting the if (currentNode == nullptr) block into the base case, which solves the problem.
I just ran into this piece of code that does this :
delete a, a = 0;
It compiles and runs just fine. But isn't this supposed to be :
delete a;
a = 0;
Why is separating statements using , allowed in this case ?
Thanks :)
In C and C++, most "statements" are actually expressions. The semicolon added to an expression makes it into a statement. Alternatively, it is allowed (but almost always bad style) to separate side-effectful expressions with the comma operator: the left-hand-side expression is evaluated for its side-effects (and its value is discarded), and the right-hand-side expression is evaluated for its value.
This is the comma-operator. It evaluates both it's arguments and returns the second one.
This is the comma operator. It can be used to separate expressions, but not declarations.
That is comma operator. MSDN article is here. And have a look at this question to understand how it works.
While it is possible to write code like that, it may be somewhat weird. A slightly more realistic usecase would be if you have a struct T as follows:
struct T {
bool check() const;
void fix();
};
Now you want to iterate through everything in the struct and run check on it, and then call fix if check returns false. The simple way to do this would be
for (list<T>::iterator it = mylist.begin(); it < mylist.end(); ++it)
if (!it->check())
it->fix();
Let's pretend you want to write it in as short a way as possible. fix() returning void means you can't just put it in the condition. However, using the comma operator you can get around this:
for (auto it = mylist.begin(); it != mylist.end() && (it->check() || (it->fix(), true)); ++it);
I wouldn't use it without a particularly good reason, but it does allow you to call any function from a condition, which can be convenient.