I found the following interesting code today:
SomeFunction(some_bool_variable ? 12.f, 50.f : 50.f, 12.f)
I created a small sample to reproduce the behavior:
class Vector3f { public: Vector3f(float val) { std::cout << "vector constructor: " << val << '\n'; } }; void SetSize(Vector3f v) { std::cout << "SetSize single param\n"; } void SetSize(float w, float h, float d=0) { std::cout << "SetSize multi param: " << w << ", " << h << ", " << d << '\n'; } int main() { SetSize(true ? 12.f, 50.f : 50.f, 12.f); SetSize(false ? 12.f, 50.f : 50.f, 12.f); }
(Live Sample)
The result I get from running the above code is:
clang++ -std=c++14 -O2 -Wall -pedantic -lboost_system -lboost_filesystem -pthread main.cpp && ./a.out main.cpp:29:20: warning: expression result unused [-Wunused-value] SetSize(true ? 12.f, 50.f : 50.f, 12.f); ^~~~ main.cpp:30:21: warning: expression result unused [-Wunused-value] SetSize(false ? 12.f, 50.f : 50.f, 12.f); ^~~~ 2 warnings generated. SetSize multi param: 50, 12, 0 SetSize multi param: 50, 12, 0
What I was expecting in both cases was that a single parameter would be passed to SetSize(float)
. However, two parameters are passed which I find extremely confusing (especially since ternary has precedence over comma; so I assumed the comma was not delimiting function arguments in this case). For example, if using true
, the ternary should result in 12.f, 50.f
. In this expression, the value to the left of the comma gets dropped/ignored, so I'd expect the end result to be:
SetSize(50.f);
The second part of the confusion is that whether we use true
or false
in the ternary, the same 2 values are passed to the function. The true
case should be h=12, w=50
I'd think...
I see the compiler is trying to warn me about something, but I can't quite understand what's going on. Can someone decompose this logic and explain the result in a step by step fashion?
The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark ( ? ), then an expression to execute if the condition is truthy followed by a colon ( : ), and finally the expression to execute if the condition is falsy.
It is not faster. There is one difference when you can initialize a constant variable depending on some expression: const int x = (a<b) ?
Example: C Ternary Operator Here, age >= 18 - test condition that checks if input value is greater or equal to 18. printf("You can vote") - expression1 that is executed if condition is true. printf("You cannot vote") - expression2 that is executed if condition is false.
Ternary Operators in C/C++The operators, which require three operands to act upon, are known as ternary operators. It can be represented by “ ? : ”. It is also known as conditional operator. The operator improves the performance and reduces the line of code.
While the second part of the ternary operator is self contained, the third part is not. The grammar is as follows:
conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
So your function call is effectively this:
SetSize((true ? (12.f, 50.f): 50.f), 12.f)
So the ternary expression true ? (12.f, 50.f): 50.f
gets evaluated as the first parameter to the function. Then 12.f
is passed as the second value. The comma in this case is not the comma operator but the function parameter separator.
From section 5.18 of the C++ standard:
2 In contexts where comma is given a special meaning, [ Example: in lists of arguments to functions (5.2.2) and lists of initializers (8.5) — end example ] the comma operator as described in Clause 5 can appear only in parentheses. [ Example:
f(a, (t=3, t+2), c);
has three arguments, the second of which has the value 5 . — end example ]
If you want the last two subexpressions to be grouped together, you need to add parenthesis:
SetSize(true ? 12.f, 50.f : (50.f, 12.f)); SetSize(false ? 12.f, 50.f : (50.f, 12.f));
Now you have a comma operator and the single argument version of SetSize
gets called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With