I expect the code below to print Test::Test(string,string,bool), however it prints Test::Test(string,bool). Why does it call the constructor that takes only one string parameter when two are provided? Surely a string can't be converted to a bool...? I have tried adding the explicit keyword but it does not help.  Code is also at http://ideone.com/n3tep1.
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
    Test(const string& str1, bool flag=false)
    {
        cout << "Test::Test(string,bool)" << endl;
    }
    Test(const string& str1, const string& str2, bool flag=false)
    {
        cout << "Test::Test(string,string,bool)" << endl;
    }
};
int main()
{
    Test* test = new Test("foo", "bar");
}
                The type of the argument being used to construct Test is char const[4].
char const[4] decays to char const*, and has to be converted to a bool or  a std::string const& to make the function call unambiguous.
A pointer can be converted to bool using standard conversion rules.
A char const* can be converted to std::string const& using a user defined conversion rule.
Given that, the conversion from char const*, a pointer, to bool is considered a better match than the conversion from char const* to std::string const&.
Hence, the call resolves to the first constructor.
"bar" is of type char const [4], and the conversion from that to a bool is an standard conversion sequence, while conversion to std::string is a user defined conversion. The former is always preferred over the latter.
From N3337, [conv]/1
Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:
— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.
— Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.
— Zero or one qualification conversion.
In your example, the standard conversion sequence consists of array-to-pointer conversion and boolean conversion.
[conv.array]/1
An lvalue or rvalue of type “array of
N T” or “array of unknown bound ofT” can be converted to a prvalue of type “pointer toT”. The result is a pointer to the first element of the array.
[conv.bool]/1
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 tofalse; any other value is converted totrue. ...
Thus Test("foo", "bar") results in a call to the Test(const string&, bool) constructor instead of the other one.
One way to trigger a call to the other constructor would be to use string_literals
using namespace std::literals::string_literals;
Test("foo", "bar"s);  // calls Test(const string&, const string&, bool)
//               ^ 
                        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