what's the correct behaver about the following code ? ( C++
standard )
I got a very strange result....
class MyClass
{
public:
MyClass(const char* p)
{
printf("ctor p=%s\n", p);
}
operator const char*() const
{
printf("IN operator const char*() const\n");
return "abcd";
}
};
const char* MyTest()
{
printf("IN const char* MyTest()\n");
return _T("efg");
}
int test1(int v)
{
bool b = false;
MyClass s1( "obj1" );
const char* lp = NULL;
lp = (b ? s1 : MyTest()); // lp will be "abcd" !!! strange!?, it
create a temp object !?
// if write the follwing way lp will be "efg"
// if (b)
// {
// lp = s1;
// }
// else
// {
// lp = MyTest();
// }
printf("lp=%s\n", lp);
return 0;
}
ctor p=obj1
IN const char* MyTest()
ctor p=efg
IN operator const char*() const
lp=abcd
That's a very out of date compiler, but I get the same results
with VC8. Both Sun CC and g++ give an error on the ?: operator,
however, and I'm pretty sure that this is what the standard
requires: the rules for type matching in a?b:c start with:
[Cases where b or c have type void elided...]
Otherwise, if the second and third operand have
different types, and either has (possibly cv-qualified)
class type, an attempt is made to convert each of those
operands to the type of the other. The process for
determining whether an operand expression E1 of type T1
can be converted to match an operand expression E2 of
type T2 is defined as follows:
-- If E2 is an lvalue: E1 can be converted to match E2
if E1 can be implicitly converted (clause 4) to the
type "lvalue reference to T2", subject to the
constraint that in the conversion the reference must
bind directly (8.5.3) to E1.
[This should fail, because the result of the
conversion will not bind directly the char const*
which corresponds to E1 in one case, an because the
char const* is not an lvalue in the other.]
-- If E2 is an rvalue, or if the conversion above
cannot be done:
-- if E1 and E2 have class type, [... obviously not
relevant, since char const* doesn't have class
type].
-- Otherwise (i.e., if E1 or E2 has a nonclass
type, or if they both have class types but the
underlying classes are not either the same or
one a base class of the other): E1 can be
converted to match E2 if E1 can be implicitly
converted to the type that expression E2 would
have if E2 were converted to an rvalue (or the
type it has, if E2 is an rvalue).
[This one applies in double, since char const*
can be converted to a MyClass, and MyClass can
be converted to a char const*.]
Using this process, it is determined whether the second
operand can be converted to match the third operand, and
whether the third operand can be converted to match the
second operand. If *both* *can* *be* *converted*
[emphasis added], or one can be converted but the
conversion is ambiguous, the program is ill-formed. If
neither can be converted, the operands are left
unchanged and further checking is performed as described
below. If exactly one conversion is possible, that
conversion is applied to the chosen operand and the
converted operand is used in place of the original
operand for the remainder of this section.
Since both can be converted, the program is ill-formed (and we
don't go any further). I suspect that VC++ has overlooked the
constraint in the first point---that the result of the
conversion must bind directly the the expression. (In practice,
I think this constraint means that only conversions to
references can be considered, but I don't find it really that
clear.)