I am able to find plenty of information about implicit conversion from, say, an int to a user defined type. i.e. if a constructor takes an int as its parameter and is not prefaced by "explicit" then implicit conversions can occur.
What if I want my class to implicitly convert to an int?
For example, what function needs to be added either inside or outside of SimpleClass such that the main function will compile and output "1" to the console? (see comments)
#include <iostream>
class SimpleClass
{
private:
int m_int;
public:
SimpleClass(int value)
: m_int(value) {}
};
int main(int argc, const char * argv[])
{
SimpleClass simpleclass(1);
int i = simpleclass; // does not complile
std::cout << i << std::endl; // should output "1" to the console
return 0;
}
Implicit conversions can be defined in two ways:
The later allows defining conversion from class type to primitive type. Just add
class SimpleClass {
// ...
operator int() const;
};
SimpleClass::operator int() const
{
return m_int;
}
Conversion to (almost) any type T
can be performed by an operator T
member function.
It is by default invoked implicitly, and if you declare it const
it can also be invoked on a const
object.
Thus:
struct MyType
{
operator int() const { return 1; }
};
Having a an implicit conversion to basic type allows free play for all the built-in operators, including
So you better make sure that all this works the way you want.
And that can be a lot of work!
There are also potential problems with overload resolution for calls involving instances of your type.
In short, implicit conversion to int
, or pointer, or any built-in type, usually costs more than it's worth.
An exception where it can be worthwhile is when a class is used a lot, in a library.
Avoid implicit conversion, but do offer explicit conversion.
The best general explicit conversion is, IMHO, a named member function.
An alternative is an operator T
prefixed with the keyword explicit
, which is supported for this use in C++11 and later (in C++03 it could only be used on constructors).
If you want output via <<
to behave as if an implicit conversion is performed, then just define an operator<<
.
And similarly for other situations where an implicit conversion would appear to be a general solution: just define what's appropriate for that specific situation, and avoid introducing a general implicit conversion.
To provide implicit conversion to a built-in type and yet avoid the “free for all” for built-in operators, you can use a templatized type conversion, e.g. like this:
#include <iostream>
template< class A, class B > struct Is_t_;
template< class Type > struct Is_t_<Type, Type> { using T = void; };
template< class A, class B >
using If_is_ = typename Is_t_<A, B>::T;
struct Bad_string
{
operator const char* () const { return "666!"; }
Bad_string( char const* = 0 ) {}
};
auto operator==( Bad_string const&, Bad_string const& )
-> bool
{ return true; }
struct Good_string
{
template< class Type, class Enabled_ = If_is_<const char*, Type>>
operator Type() const { return "42 :)"; }
Good_string( char const* = 0 ) {}
};
auto operator==( Good_string const&, Good_string const& )
-> bool
{ return true; }
#if defined( DO_GOOD )
using String = Good_string;
#elif defined( DO_BAD )
using String = Bad_string;
#else
# error "Define either DO_GOOD or DO_BAD, please."
#endif
auto main() -> int
{
String a, b;
(void) (a == "alfalfa"); // Errs for Bad_string
(void) (a + 1); // Compiles for Bad_string.
}
Ironically, when DO_GOOD
is defined this code crashes the Visual C++ 2015 update 1 compiler, a so called “ICE” (Internal Compiler Error).
A workaround for that compiler is to instead define If_is_
as
template< class A, class B >
using If_is_ = std::enable_if_t< std::is_same<A, B>::value >;
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