Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion with commas in ternary expression

Tags:

c++

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?

like image 260
void.pointer Avatar asked May 31 '17 23:05

void.pointer


People also ask

How do you handle 3 conditions in a ternary operator?

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.

Is ternary faster than if-else C?

It is not faster. There is one difference when you can initialize a constant variable depending on some expression: const int x = (a<b) ?

Which is the correct example of a ternary operator?

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.

What is a conditional ternary operator in C?

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.


1 Answers

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.

like image 143
dbush Avatar answered Oct 29 '22 11:10

dbush