Re: Conversion constructor vs. conversion operator
Am 04.05.2011 00:21, schrieb Matthias Hofmann:
"Jeffrey Schwab"<jeff@schwabcenter.com> schrieb im Newsbeitrag
news:fb8a16ec-ccf3-4a2c-b8b3-a99744bd3858@glegroupsg2000goo.googlegroups.com
....
On Monday, May 2, 2011 3:22:39 PM UTC-4, Matthias Hofmann wrote:
I was wondering whether there are any general guidelines as to when a
class
should define a conversion operator rather than conversion constructor?
There is almost never a good reason to provide implicit conversion
operators; always prefer conversion constructors. The only common
exception to this rule is provide a conversion to a boolean type, so that
objects (e.g., smart pointers) can be used in boolean contexts.
So a conversion constructor should be provided if *explicit* conversion is
wanted, with the constructor declared as "explicit", while an conversion
operator is meant to enable *implicit* conversion. I think that's a good
rule of thumb and justifies the following member function template
typically
found in smart pointers to enable implicit inheritance based type
conversion:
template<typename T>
class SmartPtr
{
T* m_ptr;
public:
template<typename U>
operator SmartPtr<U>()
{
return SmartPtr<U>( m_ptr );
}
};
A converting constructor is always a non-explicit constructor, see
[class.conv.ctor] p. 1. Your example does not match to what Jeffrey
writes and it turns out that all (new) standard smart pointers provide
converting constructors and no non-explicit conversion functions. In
case of smart pointers it also makes sense to constrain these function
template constructors to reject all those, where the pointer type is not
implicitly convertible to the target pointer.
But then I have to implement operator+() and many other operators used in
mixed expressions for my UDT. Wouldn't it be easier to simply convert my
UDT
to a built-in type and have the compiler use the built-in operators?
This makes not much sense to me. Typically user-defined arithmetic-types
provide advantages over the built-in types that you want to conserve
(e.g. much more precision or special arithmetic behaviour like what
decimal types provide). I doubt that you want to loose all these
advantages by going into the built-in value domain and perform the
algebra in built-in types.
Besides, what if I need to pass my UDt to a function that takes a built-in
type as an argument?
Speaking of arithmetic-like types, you could either provide overloads
based on the UDT (I'm thinking here of numeric functions like abs, log,
etc), or you typically provide explicitly "named" converting functions,
e.g. to_double() or some such. A similar function is the
well-established get() function of smart pointer classes.
I understand the basic concept of a moving constructor, but I don't know
how
the upcoming C++ standard is going to provide special support for this. I
hope it's not going to get complicated? Sometimes it already seems hard
for
me to catch up with all the present features, one day I understand how it
works, the next day it's deprecated...
If you have not worked yet with unique_ptr you really have missed
something - I mean that seriously. Working with unique_ptr's "moving
around" is IMO very easy to understand and you actually have to think
*less* about possible unwanted consequences or your code - I doubt that
you will miss auto_ptr a second. IMO unique_ptr is really one of the
genius, simple, "must-have" types of C++0x.
And how do I prevent ambiguities when the compiler has to choose
between a constructor and an operator to perform a conversion?
Don't define implicit conversion operators, except to some hard-to-abuse
type used strictly in boolean contexts (e.g., pointer to private member).
You mean something like this?
class MyClass
{
int* m_ptr;
public:
operator bool()
{
return m_ptr != NULL;
}
};
Don't do this! Providing an *implicit* conversion to bool brings you
near to hell! You will be astonished how many unexpected arithmetic
operations will be easily considered.
It's even worse than the old trick to provide an implicit conversion to
void* which was used in the old IO-library and which has been changed to
an explicit conversion function to bool as of C++0x standardization.
Jeff is describing the better emulation where an implicit conversion
function to a pointer to member type is provided, like this:
class MyClass
{
int* m_ptr;
struct ConversionResult { int m; };
typedef int ConversionResult::* conv_t;
public:
operator conv_t() const
{
return m_ptr != NULL ? &ConversionResult::m : NULL;
}
};
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]