views:

291

answers:

6

Hi,

I have a class like this one:

class Test{
public:
  Test(string value);
  Test(bool value);

};

If I create an object like this:

Test test("Just a test...");

The bool constructor is called!

Anyone knows why?

Thanks

+15  A: 

The type of "Just a test..." is const char *, which can be implicitly converted to either bool or std::string. Because std::string isn't a built in type, the const char *s is converted to a bool. You can prevent that by explicitly converting the const char * to a std::string:

Test test(std::string("Just a test..."));
Bill Carey
The fix is right, but the explanation is not completely correct. You *can* implicitly convert from `const char*` to `std::string` (via one of `std::string`'s constructors). It's just that the bool conversion is preferred.
Tyler McHenry
I'll make that change - thanks!
Bill Carey
"Just a test..." is not char*. In C++ it is char const[].
Maxim Yegorushkin
Fair enough - but when it's passed as an argument to the std::string constructor, it's converted to a const char *, right?
Bill Carey
Yes, standard array to ponter decay.
Maxim Yegorushkin
The explanation might benefit by being a bit more detailed: any data pointer can be converted to an integral type, and `bool` in C++ is an integral type.
David Thornley
I noticed my answer never got voted up or any comments, I am wondering if there is something wrong with it?
KennyCason
+4  A: 

The type of "Just a test..." is const char*. There is a built-in conversion from pointers to bool which is preferred over the non-built-in conversion from const char* to std::string.

The reason that the bool conversion is preferred is because std::string, while part of the standard library, is not a built-in type like integers, pointers, and booleans. It acts like any other class, and so its conversion constructors are considered only after conversions to built-in types.

Tyler McHenry
+8  A: 

This is a well known C++ annoyance.

Your string literal has type of chat const[]. You've got two constructors, conversion sequences from char const[] to Test look like this:

1) char const[] -> char const* -> bool

2) char const[] -> char const* -> std::string

1) is a built-in standard conversion whereas 2) is a user-defined conversion. Built-in conversions have precedence over user defined conversions, thus your string literal gets converted more easily to bool than to std::string.

Maxim Yegorushkin
A: 

One way is to create a variable of type std::string and pass the variable in:

std::string test = "TEST";
A a(test);

This way the type is explicitly defined as std::string it won't default to the constructor that accepts bool

KennyCason
+3  A: 

One way to circumvent this problem, is to provide another constructor taking a const char* and then converting explicitly to a std::string.

milan1612
+1  A: 

When you have a constructor (especially multiple constructors) that take only a single argument, it may be suitable to declare them "explicit" to avoid these kind of surprises. This forces the user of the class to make sure he gives the correct type to the constructor he wishes to use and prevents these implicit type conversions from being done behind the users back and hiding hard to find bugs.

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=15&rll=1

In C++0x, this has been extended to conversion operators to prevent the same issue

http://www2.research.att.com/~bs/C++0xFAQ.html#explicit-convertion

David