I have a class with an overloaded conversion operator like this:
template <class T> class Pointer {
T* object;
public:
Pointer (T* object): object(object) {}
operator T* () { return object; }
};
I noticed that some operators that I would normally have to manually overload now suddenly work as if Pointer
were a T*
but some operators don't:
MyClass my_object;
Pointer<MyClass> pointer (&my_object);
if (pointer) { /* ... */ } // works
if (pointer == &my_object) { /* ... */ } // works
(*pointer).some_method (); // works
pointer->some_method (); // doesn't work
pointer = pointer + 1; // works
pointer++; // doesn't work
Assuming this is correct behaviour according to the standard, how do I know what works and what doesn't (without trial and error) and more importantly, why is it that way?
Some of above operations work because compiler can convert custom type: Pointer<MyClass>
to raw pointer: MyClass*
implicitly using SINGLE user-defined conversion. There are strict rules for implicit conversions, described here .
Implicit conversions are performed whenever an expression of some type T1 is used in context that does not accept that type, but accepts some other type T2, in particular:
(1) When the expression is used as the argument when calling a function that is declared with T2 as parameter. (2) When the expression is used as an operand with an operator that expects T2 (3) When initializing a new object of type T2, including return statement in a function returning T2. (4) When the expression is used in a switch statement (T2 is integral type) (5) When the expression is used in an if statement or a loop (T2 is bool)
Some investigation with above example, I'll be grateful if someone could verify or correct my deductions.
case (5), if
statement:
if (pointer) { /* ... */ } // works
case (2), operator==
with operand which can be implicitly converted to MyClass*
:
if (pointer == &my_object) { /* ... */ } // works
case (2), indirection ( operator*
) taking operand which can be implicitly converted to MyClass*
, then structure reference ( operator.
):
(*pointer).some_method (); // works
does not match any of cases, operator->
does not take any argument(s), which can be implicitly converted:
pointer->some_method (); // doesn't work
case (2): operator+
taking operand which can be implicitly converted to MyClass*
and assign return value to Pointer<MyClass>
using constructor and operator=
; note that adding explicit
to constructor prevents from compiling because return type of expression: pointer + 1
is MyClass*
, so constructor taking MyClass*
is implicitly called:
pointer = pointer + 1; // works
does not match any of cases; note that even explicit convertion to MyClass*
(ex. static_cast<MyClass*>(pointer)++
) won't help, because lvalue is needed here; the workaround is: auto ptr = &(*pointer); ptr++;
auto ptr = &(*pointer); ptr++;
:
pointer++; // doesn't work
Remember, that overloading the conversion operator could sometimes lead to dangerous situations, ex. MyClass* ptr = pointer; delete ptr;
will delete underlying resource and compiler won't even complain.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.