By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,991 Members | 1,887 Online
Bytes IT Community
+ Ask a Question
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
Share this Question
Share on Google+
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=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

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

((a < b) ? p : q)[10] = 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 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

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

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

-cd


Apr 27 '07 #5

P: n/a

"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

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" <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 discussion thread is closed

Replies have been disabled for this discussion.