473,387 Members | 1,673 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

left handed use of conditional

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 1766
>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.
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
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[100], q[100];

((a < b) ? p : q)[10] = 0; // zero out 10th element of *p or *q

-cd


Apr 27 '07 #3
Sorry I did not mean to send you an email...
>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.
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
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[100], q[100];

((a < b) ? p : q)[10] = 0; // zero out 10th element of *p or *q

-cd


Apr 27 '07 #5

"David Anton" <Da********@discussions.microsoft.comwrote in message
news:F5**********************************@microsof t.com...
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
Your class example also did not compile for me. However when I deleted the
class construct and moved the definitions for f() & g() to before test it
did compile:

int f(int i) { return i - 1;}
int g(int i) { return i + 1;}

int test(int i) {
int a=1, b=0;
return ((a < b) ? f : g)(i);
}

(I changed the return types to make sure it worked) and worked
wonderfully...

I am confused on why this didn't work from within the class. I did try a few
permutations of things to see if I could get it to work.

class foo {
int f(int i) { return i - 1;}
int g(int i) { return i + 1;}

int test(int i) {
int a=1, b=0;
return ((a < b) ? f : g)(i);
}
};

returns the error: "term does not evaluate to a function" in VC++ (VS6)
and even making it: ((a < b) ? foo::f : foo::g)(i);
did not resolve the problem.

and foo::((a < b) ? f : g)(i); is an nonsencical as it looks.

Even tried to define all of the functions outside of the class declaration
and it generates the same error.

Just when I think I am getting to the point where I understand things!!!
Apr 27 '07 #6
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
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
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
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
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
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
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
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
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
On Apr 30, 12:14 pm, "Nicholas M. Makin" <nmaximill...@yahoo.com>
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

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

16
by: Mark Hahn | last post by:
Can users with international keyboards tell me if they have problems typing the left-quote ( ` ) character? It isn't used much in Python but we are thinking of giving it a slightly more important...
4
by: Lakshmi Narayanan | last post by:
hi all, i have this problem.i want the user of my page to only click the link with the right mouse button and open a word document using the open in new window option.if he clicks on the left...
8
by: Mason A. Clark | last post by:
Can anyone comment on the frequency (prevalence?) of pages that are stacked on the left? I see it as a concession to 800x600 screens. OK. But is there a way of using the full 1024x768 or...
8
by: Elementary Penguin | last post by:
Is there a left add unary operator ( or do I have to overload one ) ? For example: string s1 = "A"; s1 += "B"; Console.WriteLine( s1 )
4
by: Marek Kotowski | last post by:
Hi, What is the real difference between LEFT JOIN and RIGHT JOIN? Are there situations where a query with RIGHT JOIN cannot be rewritten with LEFT JOIN and tables reversed? (and vice versa). ...
7
by: ReidarT | last post by:
How do I use left, mid and right in vb.net? regards reidarT
6
by: Maverick | last post by:
There's a function in Borland C conio.h window (int left, int top, int right, int bottom) how can i provide the same function in VB.Net
6
by: kellygreer1 | last post by:
What is a good one line method for doing a "length safe" String.Substring? The VB classes offer up the old Left function so that string s = Microsoft.VisualBasic.Left("kelly",200) // s will =...
2
by: jehugaleahsa | last post by:
Hello: We need to make sure that we switch which button is used when our Windows Forms software runs on a left-handed user's computer. How do I discover this in C#? Thanks, Travis
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.