Re: Conversion constructor vs. conversion operator Organization: Arcor
Am 14.05.2011 10:19, schrieb Matthias Hofmann:
"Daniel Kr?gler"<daniel.kruegler@googlemail.com> schrieb im Newsbeitrag
news:ipq1vp$dai$1@dont-email.me...
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.
I was just about to ask you why a conversion constructor should be better
than a non-explicit conversion function when I found out that my example
could not be rewritten according to what Jeffrey writes:
template<typename T>
class SmartPtr
{
T* m_ptr;
public:
SmartPtr( T* ptr = 0 )
: m_ptr( ptr ) {}
// Now using conversion constructor
// instead of conversion operator.
template<typename U>
SmartPtr( const SmartPtr<U>& other )
: m_ptr( other.m_ptr ) {}
};
class Base {};
class Derived : public Base {};
int main()
{
SmartPtr<Derived> x;
// Error: Cannot access private
// member SmartPtr<Derived>::m_ptr.
SmartPtr<Base> y = x;
return 0;
}
I wonder how the new standard smart pointers are supposed to work if they
only use conversion constructors?
How an implementation realizes this, is an irrelevant detail- in theory
(and partially in practice), any library implementation can use
mechanism that are not supported by the pure C++ language. Of-course
most library implementations don't take advantage of this freedom, just
because they *could* do that. But this example does not require special
non-portable techniques to realize above conversion. A very simple way
to that is to assign friendship as follows
template<typename T>
class SmartPtr
{
template<typename>
friend class SmartPtr;
[..] // as before
};
Last but not least you typically don't need any friendship at all in
this example, if the smart pointer does provide a public function to
access the internally kept pointer:
template<typename T>
class SmartPtr
{
T* m_ptr;
public:
SmartPtr( T* ptr = 0 )
: m_ptr( ptr ) {}
template<typename U>
SmartPtr( const SmartPtr<U>& other )
: m_ptr( other.get() ) {}
T* get() const { return m_ptr; }
};
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! ]