#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 ?1 Answer. Show activity on this post. string is an object meant to hold textual data (a string), and char* is a pointer to a block of memory that is meant to hold textual data (a string). A string "knows" its length, but a char* is just a pointer (to an array of characters) -- it has no length information.
An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.
const char* is a mutable pointer to an immutable character/string. You cannot change the contents of the location(s) this pointer points to. Also, compilers are required to give error messages when you try to do so. For the same reason, conversion from const char * to char* is deprecated.
If you don't have the choice, using const char* gives a guarantee to the user that you won't change his data especially if it was a string literal where modifying one is undefined behavior. Show activity on this post. By using const you're promising your user that you won't change the string being passed in.
const char* is no more converted to bool. This time it's converted to string and this is the new output: This indicates that variant tries to convert other types first to bool and then to string.
When std::string was designed, neither of these was present though. That made classes that supported conversion to bool fairly difficult to keep safe. In particular, that conversion could (and would) happen in lots of cases you almost never wanted it to.
Before trying to use user-defined conversions (remember that std::string is a user-defined class for this purpose), the compiler will try built-in conversions. There is no built-in conversion from const char* to int, but according to §4.12 in the standard:
I have declared a boost::variant which accepts three types: string, bool and int. The following code is showing that my variant accepts const char* and converts it to bool. Is it a normal behavior for boost::variant to accept and convert types not on its list? const char* is no more converted to bool.
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.
"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`
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With