casting my smart pointer up and down

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ingo Nolden

    casting my smart pointer up and down

    Hi there,

    I am writing a smart pointer that is similar to the boost intrusive ptr.
    I am trying to make it behave like a c++ pointer including the implicit
    and explicit casting behaviour.
    Below is the part more or less relevant to my problem.

    Version 1 is fine for casting to a derived class, but it must be called
    explicitly even though it is used to cast to a base class.

    Version 2 is fine for implicitly casting to a base class, but will never
    cast to a derived class

    Version 3 is really bad. It will cast to a derived class implicitly,
    which is not what I want.

    I cannot use 1 and 2 the same time, or is there a workaround that makes
    the compiler think of them as different members?

    template<typena me T>
    class THE_API Ref
    {
    public:
    Ref( void ) : _pObj( NULL ) { }
    Ref( T* Source ) {_set( Source ); }
    Ref( const Ref<T>& Source ) {_set( Source._pObj ); }

    // Version 1. would cast only explicitly
    template< typename CASTTYPE > explicit
    Ref( const Ref<CASTTYPE>& Source )
    {
    _set( static_cast<T*> ( Source.GetNativ ePtr( ) ) );
    }

    // Version 2. is implicit and performs an implicit cast
    template< typename CASTTYPE >
    Ref( const Ref<CASTTYPE>& Source )
    {
    _set( Source.GetNativ ePtr( ) );
    }

    // Version 3. is implicit but performs an explicit cast
    template< typename CASTTYPE >
    Ref( const Ref<CASTTYPE>& Source )
    {
    _set( static_cast<T*> ( Source.GetNativ ePtr( ) ) );
    }

    template< typename CASTTYPE >
    explicit
    Ref( CASTTYPE* source )
    { // error C2440: Did you cast T* to Ref<Ref<T> > ?
    _set( static_cast<T*> ( source ) );
    }

    private:
    void _dec( ) { if( _pObj ) if ( !(--(_pObj->_refCount) ) )
    delete _pObj; }
    void _inc( ) { if( _pObj ) ++(_pObj->_refCount); }
    void _set( T* Ptr ) { _pObj = Ptr; _inc( ); }
    };
  • Siemel Naran

    #2
    Re: casting my smart pointer up and down

    "Ingo Nolden" <ingo.noldenN@S PAMrecurdyn.org > wrote in message
    news:cpiab9$tf5 $1@svr7.m-online.net...
    [color=blue]
    > // Version 1. would cast only explicitly
    > template< typename CASTTYPE > explicit
    > Ref( const Ref<CASTTYPE>& Source )
    > {
    > _set( static_cast<T*> ( Source.GetNativ ePtr( ) ) );
    > }
    >
    > // Version 2. is implicit and performs an implicit cast
    > template< typename CASTTYPE >
    > Ref( const Ref<CASTTYPE>& Source )
    > {
    > _set( Source.GetNativ ePtr( ) );
    > }
    >
    > // Version 3. is implicit but performs an explicit cast
    > template< typename CASTTYPE >
    > Ref( const Ref<CASTTYPE>& Source )
    > {
    > _set( static_cast<T*> ( Source.GetNativ ePtr( ) ) );
    > }[/color]

    I like version 2 because it seems the safest, and allows for the usual
    construct

    Ref<Base> f() {
    Ref<Derived> out(new Derived);
    ...
    return out;
    }

    As for static_cast or dynamic_cast from the base to the derived class, with
    ordinary pointers one writes

    Derived * d = static_cast<Der ived *>(b);

    But static_cast and dynamic_cast cannot be overloaded. So you could add new
    member functions. Eg.

    template <class T>
    class Ref {
    public:
    template <class U>
    Ref<U> do_dynamic_cast () const {
    return Ref<U>(dynamic_ cast<U*>(GetNat ivePtr()));
    }
    };

    Ref<Base> b = f();
    Ref<Derived> d = b.template do_dynamic_cast <Derived>(b);


    There might be better soultions with operator conversions, etc.


    Comment

    • Ingo Nolden

      #3
      Re: casting my smart pointer up and down

      Siemel Naran wrote:[color=blue]
      > "Ingo Nolden" <ingo.noldenN@S PAMrecurdyn.org > wrote in message
      > news:cpiab9$tf5 $1@svr7.m-online.net...
      >
      >[color=green]
      >>// Version 1. would cast only explicitly
      >> template< typename CASTTYPE > explicit
      >> Ref( const Ref<CASTTYPE>& Source )
      >> {
      >> _set( static_cast<T*> ( Source.GetNativ ePtr( ) ) );
      >> }
      >>
      >>// Version 2. is implicit and performs an implicit cast
      >> template< typename CASTTYPE >
      >> Ref( const Ref<CASTTYPE>& Source )
      >> {
      >> _set( Source.GetNativ ePtr( ) );
      >> }
      >>
      >>// Version 3. is implicit but performs an explicit cast
      >> template< typename CASTTYPE >
      >> Ref( const Ref<CASTTYPE>& Source )
      >> {
      >> _set( static_cast<T*> ( Source.GetNativ ePtr( ) ) );
      >> }[/color]
      >
      >
      > I like version 2 because it seems the safest, and allows for the usual
      > construct[/color]

      it is as safe as 1. but both have a lack of capability.
      1. is not able to cast to base implicitly ( but c++ pointer can do )
      2. is not able to cast to derived class explicitly
      ( but c++ pointer can do )
      And my golden goal is to achieve behaviour as close as possible to c++
      pointer[color=blue]
      >
      > Ref<Base> f() {
      > Ref<Derived> out(new Derived);
      > ...
      > return out;
      > }[/color]

      yes it does. This and any other cast to base is possible.[color=blue]
      >
      > As for static_cast or dynamic_cast from the base to the derived class, with
      > ordinary pointers one writes
      >
      > Derived * d = static_cast<Der ived *>(b);[/color]

      yes, thats what I want with it
      Ref<Derived> d = static_cast<Ref <Derived> >( b );

      I use my own RTTI and I can ask any object for its runtime type and
      verify any IS A relation. I could even make the cast checked, and throw
      an appropriate exception.
      [color=blue]
      >
      > But static_cast and dynamic_cast cannot be overloaded. So you could add new
      > member functions. Eg.
      >
      > template <class T>
      > class Ref {
      > public:
      > template <class U>
      > Ref<U> do_dynamic_cast () const {
      > return Ref<U>(dynamic_ cast<U*>(GetNat ivePtr()));
      > }
      > };
      >
      > Ref<Base> b = f();
      > Ref<Derived> d = b.template do_dynamic_cast <Derived>(b);
      >[/color]
      What is b.template? Sure you meant it like this?

      Even though what you wrote is close to my goal. I already used folloing:

      Ref< Base > b = d.as< Base >( );

      This is using a template member function on the Ref-class.
      It could also be used like a non-member template function.

      Ref< Base > b = ref_cast< Base >( d );

      Thats probably what you meant.


      I must say that you led me back to a point where I have been, but forgot
      in the meanwhile. If I make above method consistent all over the
      project, I won't need to use the static_cast and it even writes shorter
      and is nearly as descriptive as the static_cast.

      [color=blue]
      >
      > There might be better soultions with operator conversions, etc.
      >
      >[/color]
      So, if someone knows a way to get the last little step to make it really
      like c++ pointers, go go go...

      Ingo

      Comment

      • Siemel Naran

        #4
        Re: casting my smart pointer up and down

        "Ingo Nolden" <ingo.noldenN@S PAMrecurdyn.org > wrote in message
        news:cpkrpg$9k7
        [color=blue][color=green]
        > > Ref<Base> b = f();
        > > Ref<Derived> d = b.template do_dynamic_cast <Derived>(b);
        > >[/color]
        > What is b.template? Sure you meant it like this?[/color]

        It's required by the standard. It tells the compiler to parser to interpret
        the < as the beginning of a template declaration rather than the less than
        operator.
        [color=blue]
        > Ref< Base > b = ref_cast< Base >( d );
        >
        > Thats probably what you meant.[/color]

        Yes, that's good. By not using member functions, you don't have to use the
        ugly .template syntax.[color=blue]
        >
        > I must say that you led me back to a point where I have been, but forgot
        > in the meanwhile. If I make above method consistent all over the
        > project, I won't need to use the static_cast and it even writes shorter
        > and is nearly as descriptive as the static_cast.
        >
        >[color=green]
        > >
        > > There might be better soultions with operator conversions, etc.
        > >
        > >[/color]
        > So, if someone knows a way to get the last little step to make it really
        > like c++ pointers, go go go...
        >
        > Ingo[/color]


        Comment

        • Ingo Nolden

          #5
          Re: casting my smart pointer up and down

          Siemel Naran wrote:[color=blue]
          > "Ingo Nolden" <ingo.noldenN@S PAMrecurdyn.org > wrote in message
          > news:cpkrpg$9k7
          >
          >[color=green][color=darkred]
          >>>Ref<Base> b = f();
          >>>Ref<Derive d> d = b.template do_dynamic_cast <Derived>(b);
          >>>[/color]
          >>
          >>What is b.template? Sure you meant it like this?[/color]
          >
          >
          > It's required by the standard. It tells the compiler to parser to interpret
          > the < as the beginning of a template declaration rather than the less than
          > operator.
          >[/color]

          I have never seen such syntax before and I cannot imagine *what* it is.
          Can you post the declaration of that function?
          Especially wether it is a member function or not. Because you write "b"
          two times in that line.

          [color=blue]
          >[color=green]
          >>Ref< Base > b = ref_cast< Base >( d );
          >>
          >>Thats probably what you meant.[/color]
          >
          >
          > Yes, that's good. By not using member functions, you don't have to use the
          > ugly .template syntax.[/color]

          Does that mean your version was a member function? Why do you pass it
          the b as an argument?

          Also my other version that writes like:
          Ref< Derived > d = b.as< Derived >( );

          is quite direct, and works well without "b.template ".

          Comment

          • Siemel Naran

            #6
            Re: casting my smart pointer up and down

            "Ingo Nolden" <ingo.noldenN@S PAMrecurdyn.org > wrote in message[color=blue]
            > Siemel Naran wrote:[/color]
            [color=blue][color=green][color=darkred]
            > >>>Ref<Base> b = f();
            > >>>Ref<Derive d> d = b.template do_dynamic_cast <Derived>(b);[/color][/color][/color]

            BTW, I have one too many b's. Should have been
            [color=blue][color=green][color=darkred]
            > >>>Ref<Derive d> d = b.template do_dynamic_cast <Derived>();[/color][/color][/color]

            [color=blue]
            > I have never seen such syntax before and I cannot imagine *what* it is.
            > Can you post the declaration of that function?[/color]

            template <class T> Ref {
            public:
            template <class U>
            Ref<U> do_dynamic_cast () const;
            };
            [color=blue]
            > Especially wether it is a member function or not. Because you write "b"
            > two times in that line.[/color]

            Mistake on my part. There should be just one b.

            [color=blue][color=green][color=darkred]
            > >>Ref< Base > b = ref_cast< Base >( d );
            > >>
            > >>Thats probably what you meant.[/color]
            > >
            > >
            > > Yes, that's good. By not using member functions, you don't have to use[/color][/color]
            the[color=blue][color=green]
            > > ugly .template syntax.[/color]
            >
            > Does that mean your version was a member function? Why do you pass it
            > the b as an argument?
            >
            > Also my other version that writes like:
            > Ref< Derived > d = b.as< Derived >( );
            >
            > is quite direct, and works well without "b.template ".[/color]

            Right, it works on your compiler. But a fully conforming compiler is
            supposed to reject it, because it does not know whether the < is the less
            than sign or a template argument list. Most compilers I've worked with
            figure it out in simple cases. So to be conformant, it should be

            Ref< Derived > d = b.template as< Derived >( );

            and it's exactly the same as my version, except for the function name.


            So to avoid the ugly .template notation, you could use

            template <class U, class T>
            Ref<U> Ref_dynamic_cas t(const Ref<T>&);


            Comment

            Working...