Why const char* implicitly converted to bool rather than std::string?
V

3

15
#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
  1. Why const char* implicitly converted to bool rather than std::string, though constructor requires explicit type ?
  2. How the implicit conversion priority applies here?
Vandiver answered 3/3, 2021 at 7:51 Comment(6)
Because it's a pointer, and all pointers can naturally be implicitly converted to bool values.Healall
@Someprogrammerdude: but the constructor is marked as explicit, why not it is referring to the type?Vandiver
Direct initialization, which you are doing, is always explicit. It would be a different matter if you did copy initialization (like mystruct obj = c;), or used c in another context where a mystruct object was expected (like calling a function expecting a mystruct object by value).Healall
You can use std::enable_if to select the desired constructor in this case.Oology
explicit disables implicit conversion of X to mystruct , not of implicit conversion of arguments types to constructor.Aerostation
@M.M: yes I understood, earlier I had assumptions that explicit meant also for argument type to constructorVandiver
F
16

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,

  1. 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.
Farrington answered 3/3, 2021 at 7:54 Comment(6)
In my humble opinion that's WEIRD. What's the point of explicit, then?Catoptrics
It stops accidental conversions, e.g: godbolt.org/z/heErYe or godbolt.org/z/7hWdon, if you couldn't call an explicit constructor in the way you've written it you'd never be able to call that constructor at allSamal
@Catoptrics It takes effect in copy initialization, but doesn't make difference in direct initialization.Farrington
@AlanBirtles Not sure what you mean with second part of your comment, how about mystruct obj( static_cast<bool>(c)); ? I think thats what OP expect to be required to call the explicit ctrCandie
@largest_prime_is_463035818 I suppose they could have defined it that way, pretty awkward thoughSamal
@Catoptrics maybe it helps to think of it like that: What is explicit in the line mystruct obj(c); is that you are explicitly creating a mystruct, while you cannot call a foo(mystruct) with a bool directly. Its the creating of a mystruct that is explicit not the parameter type to the constructorCandie
B
1

"Why const char* implicitly converted to bool rather than std::string, though constructor requires explicit type ?":

  • Standard conversion is preferred over user defined-conversions.

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`
    
Buttonhook answered 25/8, 2021 at 22:42 Comment(0)
D
0

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'

Dugout answered 31/3, 2023 at 0:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.