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!
Related
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'm wondering about the way to concatenate bools.
What I sometimes need is to get a flag whether at least one object in a list of objects has a certain value/state/is focused etc..
What I do is this:
bool bHasState( false );
for ( auto o : MyObjectList )
{
bHasState |= ( o->state() == SOME_STATE );
}
Some of my colleagues always replace this with
bHasState = bHasState || ( o->state() == SOME_STATE );
Is this just a syntactic difference, or is my way wrong, dangerous or slow?
Expanding from the comments: the main difference here is that your version always evaluates the right-hand expression, while the version with || (or the proposed if version, which is essentially the same) doesn't, as || has short-circuit evaluation.1
The performance difference boils down to balancing the cost of a branch (an easily predicted one, since it's going to be always taken until you find an element that makes bHasState true, and then always not taken) with the cost of calling state() on every item, which may be extremely cheap (if it's a straight inline accessor, so the only cost is going to be a potential cache miss) or quite costly (if state() isn't inline, performs more complex calculations or - say - has to acquire a busy mutex).2
Still, if you were to decide that branching at each iteration isn't going to be so costly, probably you should go one step further: just break out of the loop when you find the first item whose state matches what you are looking for
bool bHasState( false );
for ( auto o : MyObjectList ) {
if(o->state() == SOME_STATE) {
bHasState = true;
break;
}
}
as it's true that the || branch is going to be easily predicted, but not looping at all over irrelevant items is surely going to be faster, especially it MyObjectList contains many elements.
Incidentally, the same exact semantic can be reproduced with this horrible standard library one-liner:
bool bHasState = std::any_of(MyObjectList.begin(), MyObjectList.end(),
[](MyObject const& o) { return o->state() == SOME_STATE; });
IOW, it evaluates the right hand expression only if the left hand expression is false; somebody pointed out that, if || is overloaded, it isn't short-circuit anymore, still, here I wouldn't think this is the case - from the context we seem to be dealing with regular integers.
Notice that, if the compiler can prove that calling state() has no observable side-effects (which can be trivially done if it's just an inline getter) it may transform the && to & or the opposite as it prefers, as having or not having the branch isn't technically observable (as far as the C++ standard is concerned).
The replacement is not quite the same. Do please read on:
bHasState |= ( o->state() == SOME_STATE ); is an idiomatic way of switching on a bit if the right hand side is true, or leaving it as it is if the right hand side is false. But it does require the evaluation of o->state(), which if that's expensive, the || alternative might be better.
That said, to me the way you currently have it is perfectly clear. (Personally I'd go one stage further and remove the redundant parentheses, which make the expression appear more complicated than it really is.)
But as a rule of thumb, I also wouldn't fiddle with code that works as you can introduce really subtle bugs. Currently o->state() is always evaluated, it wouldn't be if you changed it to bHasState = bHasState || ( o->state() == SOME_STATE );, bHasState was already true, and || was not overloaded. (Note that || is not short-circuited if || is overloaded.)
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 would like to perform the following:
if(x == true)
{
// do this on behalf of x
// do this on behalf of x
// do this on behalf of x
}
Using a conditional operator, is this correct?
x == true ? { /*do a*/, /*do b*/, /*do c*/ } : y == true ? ... ;
Is this malformed?
I am not nesting more than one level with a conditional operator.
The expressions I intend to use are highly terse and simple making a conditional operator, in my opinion, worth using.
P.S. I am not asking A. Which I should use? B. Which is better C. Which is more appropriate
P.S. I am asking how to convert an if-else statement to a ternary conditional operator.
Any advice given on this question regarding coding standards etc. are simply undesired.
Don't compare booleans to true and false. There's no point because they're true or false already! Just write
if (x)
{
// do this on behalf of x
// do this on behalf of x
// do this on behalf of x
}
Your second example doesn't compile because you use { and }. But this might
x ? ( /*do a*/, /*do b*/, /*do c*/ ) : y ? ... ;
but it does depend on what /*do a*/ etc are.
Using comma operator to string different expressions together is within the rules of the language, but it makes the code harder to read (because you have to spot the comma, which isn't always easy, especially if the expression isn't really simple.
The other factor is of course that you can ONLY do this for if (x) ... else if(y) ... type conditionals state.
Sometimes, it seems like people prefer "short code" from "readable code", which is of course great if you are in a competition of "who can write this in the fewest lines", but for everything else, particularly code that "on show" or shared with colleagues that also need to understand it - once a software project gets sufficiently large, it usually becomes hard to understand how the code works WITHOUT obfuscation that makes the code harder to read. I don't really see any benefit in using conditional statements in the way your second example described. It is possible that the example is bad, but generally, I'd say "don't do that".
Of course it works (with C++11). I have not tried a solution but following Herb Sutters way you can use ether a function call or a lambda which is immediately executed:
cond ?
[&]{
int i = some_default_value;
if(someConditionIstrue)
{
Do some operations ancalculate the value of i;
i = some calculated value;
}
return i;
} ()
:
somefun() ;
I have not tried to compile it but here you have an result whih is either computed with an lambda or an normal function.
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.