Paragraph 5.16 / 3 of the C ++ 11 standard indicates that:
[...] if the second and third operands are of different types and have a (possibly cv-qualified) type class, or if both are values ββof the same value category of the same type, except for cv-qualification, an attempt is made convert each of these operands to the type of the other . [...]
So what:
[...] If both can be converted, or you can convert, but the conversion is ambiguous, the program is poorly formed. If neither can be converted, the operands remain unchanged, and further verification is performed as described below. If one conversion is possible, this conversion is applied to the selected operand and the converted operand is used instead of the original operand for the rest of this section.
In this case, only conversion from int to DummyString , since in the other direction a const wchar_t* , as far as we can go, there is no standard implicit conversion from const wchar_t* to int .
This is why the compiler complains if you remove the conversion constructor that accepts int : if this constructor did not exist, according to the paragraph above, the program would be poorly formed (the conversion would not be in any direction).
Therefore, the second operand (first choice) is considered DummyString(0) .
However, the fact that the second operand can be converted to a DummyString does not mean that the second operand will be evaluated at all. It depends on the condition, and the condition evaluates to false (unless you pass 100 arguments to the command line), which explains why you don't see the call to this constructor. In paragraph 5.16 / 1:
Group conditional expressions from right to left. The first expression is contextually converted to bool (section 4). It is evaluated and, if true, the result of the conditional expression is the value of the second expression, otherwise the third expression. Only one of the second and third expressions is evaluated. [...]
But why does your statement fail?
And why does the compiler create a copy of ds and then discard it on wchar_t* when it can just as easily throw on the original object?
Well, this is because of clauses 5.16 / 4-5:
If the second and third operands are glvalues ββof the same category of values ββand are of the same type, [...]
Otherwise, the result will be prvalue . If the second and third operands do not have the same type and have a (possibly cv-qualified) class type, overload resolution is used to determine conversions (if any) applied to operands (13.3.1.2, 13.6).
0 not a glvalue value, so the result of the conditional will be prvalue. This means evaluating the conditional operator under false will create a temporary one from ds , which is the behavior you observe.
This is stated in paragraph 5.16 / 6, which states:
The standard values ββof the Lvalue-to-rvalue conversion (4.1), the array-to-pointer conversion (4.2), and the standard conversion of the to-pointer function (4.3) on the second and third operands are performed. After these transformations, one of the following actions will be performed:
- The second and third operands are of the same type; result of this type. If the operands are of class type, the result is a temporary prvalue value for the result type, which is initialized with a copy from the second operand or third operand , depending on the value of the first operand. [...]
The condition `` the second and third operands are of the same type '', because now the operands are considered after the conversion described in 5.16 / 3 (see the beginning of this answer).
To fix your problem, you can perform an explicit conversion on the second argument:
const wchar_t* pPtr = (argc == 100) ? 0 : static_cast<const wchar_t*>(ds);
Since a standard conversion from 0 to a pointer type exists and leads to a null pointer - see paragraph 4.10 / 1.