424,991 Members | 1,887 Online Need help? Post your question and get tips & solutions from a community of 424,991 IT Pros & Developers. It's quick & easy.

left handed use of conditional

 P: n/a I was just thinking that I understood the conditional operator when I coded the following expecting it to fail: int a= 10, b= 20, c= 0; ((a < b) ? a : b) = c; // a=0 a=20; b= 10; ((a < b) ? a : b) = c; //b=0 Now since the expresion 5 = c is not valid I did not expect the above to work. But it does work. Why? I thought that the ?: operator would evaluate to the value of "a" or "b" not to some kind of pointer to the value. This really leaves me wondering how the operator works. Apr 27 '07 #1
15 Replies

 P: n/a >I was just thinking that I understood the conditional operator when I coded >the following expecting it to fail:int a= 10, b= 20, c= 0;((a < b) ? a : b) = c; // a=0a=20; b= 10;((a < b) ? a : b) = c; //b=0Now since the expresion 5 = c is not valid I did not expect the above towork. But it does work. Why? I thought that the ?: operator would evaluateto the value of "a" or "b" not to some kind of pointer to the value. Thisreally leaves me wondering how the operator works. I'm no language expert, and the usage does seem odd, but even the Comeau compiler accepts it, so I'd guess it's perfectly valid and does something like this: if ( a < b ) a = c; else b = c; Dave Apr 27 '07 #2

 P: n/a Nicholas M. Makin wrote: I was just thinking that I understood the conditional operator when I coded the following expecting it to fail: int a= 10, b= 20, c= 0; ((a < b) ? a : b) = c; // a=0 a=20; b= 10; ((a < b) ? a : b) = c; //b=0 Now since the expresion 5 = c is not valid I did not expect the above to work. But it does work. Why? I thought that the ?: operator would evaluate to the value of "a" or "b" not to some kind of pointer to the value. This really leaves me wondering how the operator works. This results from the concepts of "lvalues" and "rvalues". (Basically, an "lvalue" can be assigned-to, while an "rvalue" cannot). The conditional operator returns one of two expressions. If both expressions are l-values, then the result of the conditional is also an l-value, as you've discovered. If either expression was not an l-value, then the one that was an l-value would be subject to an "lvalue to rvalue conversion", and the result of the expression would be an r-value and not assignable. int a, b; ((a < b ) ? a : 5) = 1; // won't compile You'll find the conditional operator works in other possibly surprising cases as well: void f(int) { ... } void g(int) { ... } int a,b; ((a < b) ? f : g)(10); // calls either f or g with parameter 10 int p, q; ((a < b) ? p : q) = 0; // zero out 10th element of *p or *q -cd Apr 27 '07 #3

 P: n/a Sorry I did not mean to send you an email... >The conditional operator returns one of two expressions. If bothexpressions are l-values, then the result of the conditional is also anl-value, as you've discovered. If either expression was not an l-value,then the one that was an l-value would be subject to an "lvalue to rvalueconversion", and the result of the expression would be an r-value and notassignable. Now that makes sence. Thank you very much. As for the other examples. I did find the example with the functions a little surprising but not unexpected as the identifiers are linked to referances to the functions. I did however expect the behavior with pointers. In fact my plan had been to replace the above code with pointers and I fully expected: int *a, *b; *((*a < *b) ? a : b) = 0; To work. Everything I *thought* that I understood about the conditional operator told me that it would. What is kind of ammusing in all of this is that I was writing a tutorial on using the conditional operator. Most such tutorials just give the basic syntax and the standard example. The problem is that they never really point out that the conditional operator is an *operator* and not just a shorthand for an if-else *statement*. So I was looking for surprising examples that would help drive this point home. -- And as you can see when I tried what I *thought* would be a counter example it turned into an example. :) If you know of a good resource where I could find some more technical data or surprising examples on the conditional operator in C/C++/C# I would greatly apreciate it. Again thank you for clearing up the rvalue-lvalue. I will do more research on that so that I can explain in detail. Apr 27 '07 #4

 P: n/a Regarding the 'other surprising cases'; are you sure there's no weird compiler setting you have to have to get these to work? I tried the following (your first case) and it won't compile: class foo { void test() { int a, b; (a < b ? f : g)(10); } void f(int i) {} void g(int i) {} }; -- David Anton www.tangiblesoftwaresolutions.com Instant C#: VB to C# converter Instant VB: C# to VB converter Instant C++: C#/VB to C++ converter Instant Python: C#/VB to Python converter "Carl Daniel [VC++ MVP]" wrote: Nicholas M. Makin wrote: I was just thinking that I understood the conditional operator when I coded the following expecting it to fail: int a= 10, b= 20, c= 0; ((a < b) ? a : b) = c; // a=0 a=20; b= 10; ((a < b) ? a : b) = c; //b=0 Now since the expresion 5 = c is not valid I did not expect the above to work. But it does work. Why? I thought that the ?: operator would evaluate to the value of "a" or "b" not to some kind of pointer to the value. This really leaves me wondering how the operator works. This results from the concepts of "lvalues" and "rvalues". (Basically, an "lvalue" can be assigned-to, while an "rvalue" cannot). The conditional operator returns one of two expressions. If both expressions are l-values, then the result of the conditional is also an l-value, as you've discovered. If either expression was not an l-value, then the one that was an l-value would be subject to an "lvalue to rvalue conversion", and the result of the expression would be an r-value and not assignable. int a, b; ((a < b ) ? a : 5) = 1; // won't compile You'll find the conditional operator works in other possibly surprising cases as well: void f(int) { ... } void g(int) { ... } int a,b; ((a < b) ? f : g)(10); // calls either f or g with parameter 10 int p, q; ((a < b) ? p : q) = 0; // zero out 10th element of *p or *q -cd Apr 27 '07 #5

 P: n/a "David Anton"

 P: n/a The following construction also works: class foo { static int f(int i) { return i - 1;} static int g(int i) { return i - 1;} int test(int i){ int a=1, b=0; return ((a < b) ? f : g)(i); } }; I feel that this has to be a hint as to why the other construction did not work, but I can't quite figure it out. I tried various versions using pointers to functions and found the same error in the end. I feel as though the answer is simple and just escapeing my grasp. I also tried using this->f and this->g which did no better. Apr 28 '07 #7

 P: n/a Nicholas M. Makin wrote: The following construction also works: class foo { static int f(int i) { return i - 1;} static int g(int i) { return i - 1;} int test(int i){ int a=1, b=0; return ((a < b) ? f : g)(i); } }; I feel that this has to be a hint as to why the other construction did not work, but I can't quite figure it out. I tried various versions using pointers to functions and found the same error in the end. I feel as though the answer is simple and just escapeing my grasp. I also tried using this->f and this->g which did no better. This oddity is due to the fact that a non-member function or static member function can have it's address taken by simply referring to the name and that address is a simple function pointer. That is not true for an ordinary member function. The corresponding (extremely ugly) case for a non-member function would be something like: class X { int f(int); int g(int); int h(bool b, int a) { return (this->*(b ? &X::f : &X::g))(a); } }; -cd Apr 28 '07 #8

 P: n/a Thanks for clearing that up Carl! I'm sure very few people write code like that (since the 'if/else' is so much simpler in this case), but if we ever come across it we'll know exactly what's happening. -- David Anton www.tangiblesoftwaresolutions.com Instant C#: VB to C# converter Instant VB: C# to VB converter Instant C++: C#/VB to C++ converter Instant Python: C#/VB to Python converter "Carl Daniel [VC++ MVP]" wrote: Nicholas M. Makin wrote: The following construction also works: class foo { static int f(int i) { return i - 1;} static int g(int i) { return i - 1;} int test(int i){ int a=1, b=0; return ((a < b) ? f : g)(i); } }; I feel that this has to be a hint as to why the other construction did not work, but I can't quite figure it out. I tried various versions using pointers to functions and found the same error in the end. I feel as though the answer is simple and just escapeing my grasp. I also tried using this->f and this->g which did no better. This oddity is due to the fact that a non-member function or static member function can have it's address taken by simply referring to the name and that address is a simple function pointer. That is not true for an ordinary member function. The corresponding (extremely ugly) case for a non-member function would be something like: class X { int f(int); int g(int); int h(bool b, int a) { return (this->*(b ? &X::f : &X::g))(a); } }; -cd Apr 28 '07 #9

 P: n/a David Anton wrote: Thanks for clearing that up Carl! I'm sure very few people write code like that (since the 'if/else' is so much simpler in this case), but if we ever come across it we'll know exactly what's happening. Honestly, I can scarcely imagine a situation in which it'd be acceptable to write code like that. It's just too obscure. I wouldn't expect the compiler to do anything resembling optimization on such a construct either (but who knows - the optimizer guys pull some amazing stuff out of their hats). -cd Apr 28 '07 #10

 P: n/a Carl Daniel [VC++ MVP] wrote: true for an ordinary member function. The corresponding (extremely ugly) case for a non-member function would be something like: Oops! That should say "non-static member function" in the line above. -cd Apr 28 '07 #11

 P: n/a I noticed that, but after your fantastic explanation I wasn't going to nitpick ;) -- David Anton www.tangiblesoftwaresolutions.com Instant C#: VB to C# converter Instant VB: C# to VB converter Instant C++: C#/VB to C++ converter Instant Python: C#/VB to Python converter "Carl Daniel [VC++ MVP]" wrote: Carl Daniel [VC++ MVP] wrote: true for an ordinary member function. The corresponding (extremely ugly) case for a non-member function would be something like: Oops! That should say "non-static member function" in the line above. -cd Apr 28 '07 #12

 P: n/a In the end this is what I got working. class foo { public: int f(int i); int g(int i); int test(int i); }; int foo::f(int i) { return i - 1;} int foo::g(int i) { return i + 1;} int foo::test(int i) { int a=1, b=0; return (this->*((a < b) ? this->f : this->g))(i); } I was drawn to it by the error messages generated by various other attempts. The part that took the longest was the outside parentheses (a little lesson in what left-to-right association vs right-to-left association). I have to say I don't ever plan on using such a construction, but the process has been very instructive. Thank you both very much for the adventure. Apr 29 '07 #13

 P: n/a Nicholas M. Makin wrote: In the end this is what I got working. class foo { public: int f(int i); int g(int i); int test(int i); }; int foo::f(int i) { return i - 1;} int foo::g(int i) { return i + 1;} int foo::test(int i) { int a=1, b=0; return (this->*((a < b) ? this->f : this->g))(i); } I was drawn to it by the error messages generated by various other attempts. The part that took the longest was the outside parentheses (a little lesson in what left-to-right association vs right-to-left association). I have to say I don't ever plan on using such a construction, but the process has been very instructive. That actually shouldn't compile - it's not legal C++. Indeed, it doesn't compile with VC8 or Comeau C++ (the gold standard for C++ legality). Instead, it should read: class foo { public: int f(int i); int g(int i); int test(int i); }; int foo::f(int i) { return i - 1;} int foo::g(int i) { return i + 1;} int foo::test(int i) { int a=1, b=0; return (this->*((a < b) ? &foo::f : &foo::g))(i); } Which does compile with VC8 (VS 2005). I assume you're using an older version of the compiler that didn't get this right. -cd Apr 29 '07 #14

 P: n/a Which does compile with VC8 (VS 2005). I assume you're using an older version of the compiler that didn't get this right. -cd lol. Indeed. Apr 30 '07 #15

 P: n/a On Apr 30, 12:14 pm, "Nicholas M. Makin" wrote: Which does compile with VC8 (VS 2005). I assume you're using an older version of the compiler that didn't get this right. -cd lol. Indeed. Enjoyed the discussion! May 1 '07 #16 