Reputation: 1579
#include <iostream>
#include <string>
struct mystruct{
mystruct(std::string s){
std::cout<<__FUNCTION__ <<" String "<<s;
}
explicit mystruct(bool s) {
std::cout<<__FUNCTION__<<" Bool "<<s;
}
};
int main()
{
const char* c ="hello";
mystruct obj(c);
return 0;
}
output:
mystruct Bool 1
const char*
implicitly converted to bool
rather than std::string
, though constructor requires explicit
type ?Upvotes: 16
Views: 1690
Reputation: 5589
Just to add to the already good answer. You can work around this by adding a delegating constructor as in:
mystruct(const char* s):mystruct(std::string(s)) {}
Which will win over bool in overload resolution.
Another option is to avoid bool here and use a bool but something that carries more meaning. This could be an example of 'boolean blindness'
Upvotes: 0
Reputation: 3164
"Why const char*
implicitly converted to bool
rather than std::string
, though constructor requires explicit
type ?":
char const*
is a pointer to constant character and a pointer can be implicitly converted to bool
: in case it is nullptr
it is converted to false
otherwise to true
.
You used to see such effective conversion in conditions where you check whether the pointer is NULL
or not so in case it is not nulptr
we safely de-reference it otherwise it has nullptr
value thus it is not correct to de-reference it:
int* ptr = nullptr;
if(ptr) // false because ptr has nullptr or NULL or 0 or 0x000000 address value
std::cout << ptr << '\t' << *ptr << '\n'; // not executed
ptr = new int(10); // valid and non-nullptr
if(ptr) // non-nullptr so condition succeeds
std::cout << ptr << '\t' << *ptr << '\n'; // 0FED155 10
delete ptr; // free memory
explicit
constructor means it can only be called explicitly and the only way is through Direct Initialization like in your case:
mystruct obj(c); // direct initialization
mystruct obj = c; // copy-initialization. Error: constructor myStruct(bool) is `explicit`
Upvotes: 1
Reputation: 172984
Because the implicit conversion from const char*
to bool
is qualified as standard conversion, while const char*
to std::string
is user-defined conversion. The former has higher ranking and wins in overload resolution.
A standard conversion sequence is always better than a user-defined conversion sequence or an ellipsis conversion sequence.
BTW: mystruct obj(c);
performs direct initialization, explicit
converting constructors including mystruct::mystruct(bool)
are considered too. As the result, c
is converted to bool
then passed to mystruct::mystruct(bool)
as argument to construct obj
.
Direct-initialization is more permissive than copy-initialization: copy-initialization only considers non-explicit constructors and non-explicit user-defined conversion functions, while direct-initialization considers all constructors and all user-defined conversion functions.
About explicit
specifier,
- Specifies that a constructor
or conversion function (since C++11)
or deduction guide (since C++17)
is explicit, that is, it cannot be used for implicit conversions and copy-initialization.
Upvotes: 17