Topic: Global conversion function names / type casts (templates!) ...


Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/08/15
Raw View
In article <DD1MI7.C8H.0.-s@cs.vu.nl>, ctv <ctv@cs.vu.nl> wrote:
>
>Operator overloading can be used to implement so called smart
>pointers. Operator "=", "->", etcetera member functions allow
>these smart pointers to be used in (almost) the same way as real
>pointers.
>
>How to mimic real-pointer-like casts when the pointers are actually
>smart pointers ?

Member templates:

template<class T> class Smart {
T *data;
public:
template<class Q>
Smart(Smart<Q> const &arg) {
data = arg.data; // conversion!
}
..
};

struct Base {};
struct Derived : Base {};
Smart<Derived> pd = new Derived;
Smart<Base> = bd; // Smart pointer conversion!
Smart<Derived> bad = pb; // INSTANTIATION FAILS!

Note in the last line the conversion is CORRECT -- there's
no error here, the error occurs instantiating the
member template. If the body isn't visible you'd not
find out until link time.

--
JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA     Phone: 61-2-566-2189
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: ctv@cs.vu.nl (ctv)
Date: 1995/08/09
Raw View
Operator overloading can be used to implement so called smart
pointers. Operator "=", "->", etcetera member functions allow
these smart pointers to be used in (almost) the same way as real
pointers.

How to mimic real-pointer-like casts when the pointers are actually
smart pointers ?

Given the smart pointer template class as sketched in the second
code fragment below, I would like to have a conversion (template)
function as depicted in the first code fragment.

To what extent does this first fragment violate the current C++
definition:

  1) Is it allowed to have global (i.e. non-class member) cast
     functions (operator ConversionFunctionName() ) ?

  2) Usually (?) different instantiations of the same template
     function are based on differences in their parameters: what
     I would like to have is that class names as well as template
     class names can be used to define a generic (and user verified)
     conversion function framework like it is sketched below in:
     "template<class To, class From>" What motivation makes it
     unreasonable to expect that not only the parameters can be
     "parameterized" but also the function name because it is a
     user defined (template) class name ?

  3) In which ways does this sketch violate the current C++ definition ?
     (at least, the 5 different C++ compilers I use don't accept
     (several slightly different implementations of) this example).

Suggestions for an elegant solution ? Of course, it's possible
to define an explicit template function with a name that's not
based on a template class name, however that's not the sort of
solution I'm looking for ....

Example:

 class c1; class c2;

 ptr<c1> p1; ptr<c2> p2; // smart pointers p1, p2 to
    // instances of c1, c2

    // See code fragment 1 for:
 p2 = ptr<c2> (p1);  // function notation
     // or:
 p2 = (ptr<c2>) p1;  // cast notation


 Thanks for your help,

 -- Cees Visser

 =========  =========  =========  =========  =========  =========

 Code fragment 1:

 =========  =========  =========  =========  =========  =========

template<class To, class From> ::operator ptr<To> (ptr<From>& from)
{
   ptr<To> to;

   // run-time checks ...

   to.ptr_ = (To *) from.ptr_ ;

   return to;
}

 =========  =========  =========  =========  =========  =========

 Code fragment 2:

 =========  =========  =========  =========  =========  =========

template<class T> class ptr {
private:

   T  *ptr_; /* real object pointer */

   void incr_refc (T* tp) {
      // ...
   }

   void decr_refc (T* tp) {
      // ...
   }

public:

   ptr (void) {
      ptr_ = 0;
   }

   ptr (const ptr& obj) {
      ptr_ = obj.ptr_;
      incr_refc (ptr_);
   }

   ptr (T *t) {
      ptr_ = t;
      incr_refc (ptr_);
   }

   ~ptr (void) {
      // ...
   }

   /* ptr assignment: */
   void operator = (ptr& obj) {
      decr_refc (ptr_);
      ptr_ = obj.ptr_;
      incr_refc (ptr_);
      return /* not *this */ ;
   }

   /* null ptr assignment: */
   void operator = (void *null_ptr) {
      decr_refc (ptr_);
      verify (null_ptr == NULL);
      ptr_ =  0;
      return /* not *this */ ;
   }

   T* operator -> () {
      verify (ptr_ != 0);
      return ptr_;
   }

   /* dereference */
   T& operator * () {
      verify (ptr_ != 0);
      return *ptr_ ;
   }

   int operator == (ptr& obj) {
      return ptr_ == obj.ptr_;
   }

   int operator != (ptr& obj) {
      return ptr_ != obj.ptr_;
   }

   friend template<class T, class F> ::operator ptr<T>(ptr<F> f);
};