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