Consider this simple example:
template <class Type> class smartref { public: smartref() : data(new Type) { } operator Type&(){ return *data; } private: Type* data; }; class person { public: void think() { std::cout << "I am thinking"; } }; int main() { smartref<person> p; p.think(); // why does not the compiler try substituting Type&? }
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
A conversion operator, in C#, is an operator that is used to declare a conversion on a user-defined type so that an object of that type can be converted to or from another user-defined type or basic type. The two different types of user-defined conversions include implicit and explicit conversions.
In C programming, we can convert the value of one data type ( int, float , double , etc.) to another. This process is known as type conversion.
Conversion Operators in C++ In C++, the programmer abstracts real-world objects using classes as concrete types. Sometimes, it is required to convert one concrete type to another concrete type or primitive type implicitly.
You can define a member function of a class, called a conversion function, that converts from the type of its class to another specified type.
Some random situations where conversion functions are used and not used follow.
First, note that conversion functions are never used to convert to the same class type or to a base class type.
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
struct B { }; struct A { operator B() { return B(); } }; void f(B); int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
B b = A(); // called!
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
struct B { }; struct A { operator B&() { static B b; return b; } }; int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
struct B { }; struct A { operator B&() { static B b; return b; } }; B &b = A(); // called!
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
typedef void (*fPtr)(int); void foo(int a); struct test { operator fPtr() { return foo; } }; int main() { test t; t(10); // called! }
This thing can actually become quite useful sometimes.
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
struct test { operator bool() { return true; } }; int main() { test t; if(t) { ... } }
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
struct test { void operator[](unsigned int) { } operator char *() { static char c; return &c; } }; int main() { test t; t[0]; // ambiguous } // (t).operator[] (unsigned int) : member // operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t
needs be different from int
then).
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
struct test { template<typename T> operator T*() { return 0; } }; void *pv = test(); bool *pb = test();
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