3

I'm a Java programmer who has been trying to learn a bit of C++ on the side to expand on my knowledge. Here is a small code snippet which I think works due to implicit conversion but I'd like to know which part of the specification does it refer to and what are the other rules which I must be aware of when it comes to implicit conversion. Is there a document/link/site out there which lays down the implicit conversion rules?

#include <vector>
#include <iostream>
#include <iterator>

int main(void) {
  using namespace std;
  vector<bool> a;
  a.push_back("asdf");
  a.push_back("");  
  a.push_back(12);  
  a.push_back(0.0);  
  copy(a.begin(), a.end(), ostream_iterator<bool>(cout, "\n"));
  return 0;
}

/*
output:

1
1
1
0
*/

TIA,
sasuke

sasuke
  • 6,589
  • 5
  • 36
  • 35
  • That would be the language specification :) – Matt K Dec 21 '11 at 14:20
  • the only rule I can give you is: try to avoid `implicit conversion` as if your life depend on it. – Roee Gavirel Dec 21 '11 at 14:20
  • 2
    The most important thing to know about your code-snippet is that `vector` is a specialization of `vector` and behaves differently in several aspects (none of which are relevant to your question though, just thought you should know). Be careful when using it. – Björn Pollex Dec 21 '11 at 14:21
  • 1
    Using vector isn't recommended in C++. – DumbCoder Dec 21 '11 at 14:22
  • 2
    @Constantinius you got that backwards – Chad Dec 21 '11 at 14:22
  • @DumbCoder: That's strange, heard it for the first time. What is recommended then? – sasuke Dec 21 '11 at 14:24
  • @mkb: AFAICT, C++ standard is not freely avaiable. Is there any site which offers material very close to the C++ standard? – sasuke Dec 21 '11 at 14:25
  • 1
    @sasuke: Here's one article that discusses the problems with `vector`: http://www.gotw.ca/gotw/050.htm – Fred Larson Dec 21 '11 at 14:28
  • @sasuke the last draft before it becomes a standard is always free. Which version are you looking for? C++03 or C++11? – Joe Dec 21 '11 at 14:29
  • @sasuke: There's no problem with using `vector` as long as you understand how it differs from other specialisations of `vector` - the data is not stored as an array of `bool`, but as packed bits. If you don't need to access the underlying array (which you usually won't), then there's no problem. – Mike Seymour Dec 21 '11 at 14:29
  • @sasuke: sure it is. You can even read the text that's *more recent* than the published standard [on GitHub](https://github.com/cplusplus/draft) (you just need to TeX it yourself). – Kerrek SB Dec 21 '11 at 14:30
  • Where to find the C++ draft standard: http://stackoverflow.com/a/4653479/10077 – Fred Larson Dec 21 '11 at 14:34
  • Just one last question: if I'm using GCC 4.X or Visual Studio 2010, which standard document should I be referring? The C++03 or C++11 one? – sasuke Dec 21 '11 at 14:37
  • @sasuke: For GCC, it depends on what the `X` is, and if you use the `std=c++0x` compile option. I don't think any version fully implements C++11 yet. I understand VS2010 implements some C++11 features as well. Might be best to go with C++03 for now. – Fred Larson Dec 21 '11 at 14:40
  • @MikeSeymour "_There's no problem with using vector_" Wrong. There is a problem with `vector`: it's broken, beyond repair, should be removed, it's required for conforming implementations, but it isn't even clear that conforming implementations are allowed to provide it!!! – curiousguy Dec 21 '11 at 16:48
  • @curiousguy: You're correct that it doesn't formally meet the Container requirements. However, it's perfectly usable if you don't require `vector::reference` to define an actual reference type, whatever your views on whether or not it should exist in the first place. As I said, there's no problem using it as long as you understand it. – Mike Seymour Dec 21 '11 at 16:54
  • @MikeSeymour `pointer` is not a pointer, `reference` is not a reference, and once you start using `v[i].flip()` (or more subtly, if you overload a function on `vector::reference` vs `bool&`) your code is not compatible with a regular `vector` or any other regular container. And the other advantages you could get from the packing (fast binary operations): you can't even get them because the binary representation is not accessible! If you really want the packing, you can implement your own `bit_vector` based on `vector`, then you don't have all these anomalies. – curiousguy Dec 21 '11 at 17:09
  • @curiousguy: I have asked it before in the comments and I ask it again: if not `vector`, then what? – sasuke Dec 21 '11 at 17:44
  • 1
    @sasuke: `vector` if you want a dynamic array of something that behaves more-or-less like `bool`; or `deque` if you want a sequence container that contains actual `bool` values; or `vector`, `boost::dynamic_bitset` (which is similar, but with a richer interface) or `std::bitset` (if the size is fixed) if you want to minimise memory usage, and don't mind that it's not a bona fide container. – Mike Seymour Dec 22 '11 at 11:21

2 Answers2

9

Pointers and integers, and also booleans, are integral types. The first three are all either pointers or integers, and since they are all non-zero, they convert to the boolean value true. The fourth value of type double converts to a zero integral value and hence false.

Conversion of doubles that are not representable as integral values (like infinity and NaN) is undefined.

See 4.9 for details, and also 4.12 for "Boolean conversions":

A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.

Your 0.0 is an arithmetic type of zero value.

Perhaps you may not be familiar with string literals in C++: "" denotes the array char[1] { 0 }, and this array (of one element) decays to a pointer to its first element, which is necessarily a non-null pointer. Similarly, "asdf" denotes an array char[5] { 'a', 's', 'd', 'f', 0 }, and again this decays to a (non-null) pointer to its first element. The actual value of the characters is entirely immaterial.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Wow, supremely complicated. Is everything you mentioned in last paragraph (decaying to pointer, "" as char[1] etc.) also part of the specification (esp the char[1] part)? – sasuke Dec 21 '11 at 14:29
  • Interesting fact about doubles. Is there a standard spec about that? – Luchian Grigore Dec 21 '11 at 14:30
  • @LuchianGrigore: Yes, I quoted it and cited relevant references. – Kerrek SB Dec 21 '11 at 14:31
  • 2
    @sasuke: It's not at all complicated, it's just a bit of a mouthful to say if you want to make an accurate statement. Most real C++ programmers have a mental shortcut, so when they see a string literal they'll think "pointer" immediately, but it's important to be accurate sometimes. – Kerrek SB Dec 21 '11 at 14:32
  • I don't see the part about doubles. "A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true." - this tells me any double that is not 0 is converted to true. Am I understanding this wrong? – Luchian Grigore Dec 21 '11 at 14:34
  • @LuchianGrigore: `double` is an arithmetic type, and `0.0` is a double of zero value... so you have an arithmetic type of zero value. What's unclear? – Kerrek SB Dec 21 '11 at 14:40
  • That part is clear, I don't understand "Conversion of doubles that are not representable as integral values (like infinity and NaN) is undefined.". – Luchian Grigore Dec 21 '11 at 14:43
  • "_Conversion of doubles that are not representable as integral values_" most double are not representable as integral values! – curiousguy Dec 21 '11 at 15:47
  • @LuchianGrigore "_Interesting fact about doubles. Is there a standard spec about that?_" no, because it's (obviously) wrong! ;) – curiousguy Dec 21 '11 at 15:49
  • That's subjective. Even if wrong, what should it be converted to? true or false? – Luchian Grigore Dec 21 '11 at 16:01
  • 1
    @LuchianGrigore Non zero values are converted to true. – curiousguy Dec 22 '11 at 22:39
2

All base types can be converted to bool implicitly. Anything that is not 0 is TRUE, and 0 is FALSE.

For user defined types, if you use pointers, anything that is not NULL is evaluates to TRUE, otherwise FALSE.

If you use object instances and not pointers, you need to declare operator bool():

class A
{
public:
   operator bool() {return false;};
};

//....

A a;
if ( a ) //compiles because of the operator
   //...;
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • Can you extrapolate on the last part, what do you mean by "object instances"? Something like `Person p;` instead of `Person* p;`? – sasuke Dec 21 '11 at 14:23
  • @sasuke exactly. I wrote a small example. – Luchian Grigore Dec 21 '11 at 14:24
  • 3
    Be aware that `operator bool()` opens a whole other can of worms - which gave rise to the [safe-bool idiom](http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool) in C++03. [Apparently this is obsolete now](http://stackoverflow.com/questions/6242768/is-the-safe-bool-idiom-obsolete), though. – Björn Pollex Dec 21 '11 at 14:25