ternary operator and ostreams

R

Roger Leigh

This code works (GCC 3.3.3):

#include <iostream>
int main()
{
bool a = true;
std::cout << "True and false\n"
<< (a == true) ? 't' : 'f';
std::cout << "\n";
return 0;
}

But this code does not:

#include <iostream>

int main()
{
bool a = true;

std::cout << "True and false\n"
<< (a == true) ? 't' : 'f'
<< "\n";

return 0;
}

test.cc: In function `int main()':
test.cc:9: error: invalid operands of types `char' and `const char[2]' to
binary `operator<<'

However, if I enclose the entire ternary expression in parentheses
"((a == true) ? 't' : 'f')" then it does compile.

What is different between these two forms? Both return a char, but
only the latter returns a std::eek:stream& when used in the above
expression.


Many thanks,
Roger
 
L

lilburne

Roger said:
What is different between these two forms? Both return a char, but
only the latter returns a std::eek:stream& when used in the above
expression.


Check operator precedence:
(a == true) ? 't' : ('f' << "\n");
 
J

Jerry Coffin

${roger} said:
This code works (GCC 3.3.3):

[ snipped ]
But this code does not:

#include <iostream>

int main()
{
bool a = true;

std::cout << "True and false\n"
<< (a == true) ? 't' : 'f'
<< "\n";

return 0;
}

This is a precedence problem -- the compiler is trying to treat this as:

(a==true)? 't' : ('f' << '\n');

I.e. trying to shift 'f' left by '\n' bits. This would actually work
(it would typically shift 'f' left by 13 bits) except for one minor
detail: the result of that bit-shift would be an int, and your other
result is 't' which is a char. The compiler does insist that both
results in a ?: be of the same type.

When '<<' is used in its traditional role (bit-shifting) it more or less
makes sense to be able to bit-shift an operand of ?: without extra
parentheses. When you're using it for I/O it usually makes less sense,
but the compiler always give the operand its original precedence and
associativity.

I'd also note that your '==true' is utterly vacuous and kind of stupid
when you think about it -- 'a' starts out as a bool, and your comparison
to true produces a bool that's always equal to a's original value.
Since a is a bool, just use it directly:

std::cout << (a ? 't' : 'f') << "\n";

If you're going to compare it to true, then you probably need to compare
the result of that comparison to true as well -- and so on indefinitely.

Also note that iostreams already support writing bools out in text
format, though they produce 'true' and 'false' instead of the 't' and
'f' you've used.
 
R

Roger Leigh

Jerry Coffin said:
${roger} said:
This code works (GCC 3.3.3):

[ snipped ]
But this code does not:

#include <iostream>

int main()
{
bool a = true;

std::cout << "True and false\n"
<< (a == true) ? 't' : 'f'
<< "\n";

return 0;
}
I'd also note that your '==true' is utterly vacuous and kind of stupid
when you think about it -- 'a' starts out as a bool, and your comparison
to true produces a bool that's always equal to a's original value.
Since a is a bool, just use it directly:

std::cout << (a ? 't' : 'f') << "\n";

That's an excellent point, thanks!
Also note that iostreams already support writing bools out in text
format, though they produce 'true' and 'false' instead of the 't' and
'f' you've used.

That's probably even better. However, I'm constructing SQL database
queries with this, and I want to ensure the "true" and "false" will
never be localised. From what I've seen you need to manually add this
facility to a locale to get localised strings? I want to avoid this
ever occuring if possible.
 
J

Jerry Coffin

[ ... ]
That's probably even better. However, I'm constructing SQL database
queries with this, and I want to ensure the "true" and "false" will
never be localised. From what I've seen you need to manually add this
facility to a locale to get localised strings? I want to avoid this
ever occuring if possible.

The default global locale is the "C" locale, which will always spell
these as "true" and "false". If you change the global locale (e.g. with
setlocale) then you may have to explicitly imbue this stream with the
"C" locale again to get the desired behavior. Given that it's crucial
for it to use the "C" locale, you might want to imbue it explicitly even
if (for now) you're never changing locales at all. IIRC, one way to do
that should be something like this:

/* warning: untested code */
std::fstream SQL_stuff("filename.sql");

std::locale def_loc("C");
SQL_stuff.imbue(def_loc);

This way, if you add localization code in the future, you're still
assured that this stream will use the default locale.
 
R

Roger Leigh

Jerry Coffin said:
[ ... ]
That's probably even better. However, I'm constructing SQL database
queries with this, and I want to ensure the "true" and "false" will
never be localised. From what I've seen you need to manually add this
facility to a locale to get localised strings? I want to avoid this
ever occuring if possible.

The default global locale is the "C" locale, which will always spell
these as "true" and "false". If you change the global locale (e.g. with
setlocale) then you may have to explicitly imbue this stream with the
"C" locale again to get the desired behavior. Given that it's crucial
for it to use the "C" locale, you might want to imbue it explicitly even
if (for now) you're never changing locales at all. IIRC, one way to do
that should be something like this:

/* warning: untested code */
std::fstream SQL_stuff("filename.sql");

std::locale def_loc("C");
SQL_stuff.imbue(def_loc);

This way, if you add localization code in the future, you're still
assured that this stream will use the default locale.

Thanks for clearing that up. I'm currently using "C", and I've
explicitly selected "C" as the default locale, but I hope to
internationalise it at some point in the near future (I need to clean
up some numeric formatting issues first). I just need to make sure
the communcation with the database (and other programs) is
standardised to use "C".

I'm using std::eek:stringstream to construct the queries, so it'll be no
big deal to explicitly imbue them with "C".


Many thanks for your help,
Roger
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top