clarification: behavior of type_info::before

This is a discussion on clarification: behavior of type_info::before within the C++ Programming forums, part of the General Programming Boards category; Code: inline bool is( type_info const & derived, type_info const & base ) { return base == derived || base.before( ...

  1. #1
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,636

    Question clarification: behavior of type_info::before

    Code:
    inline
    bool
    is( type_info const & derived, type_info const & base )
    {
        return base == derived || base.before( derived );
    } 
     
    struct base { virtual ~base( void ){   } };
     
    struct first : base {   };
     
    struct second : base {   };
     
    int 
    main( void )
    {
        assert( ( is( typeid( first ), typeid( base ) ) ) );
        assert( ( is( typeid( second ), typeid( base ) ) ) );
        assert( !( is( typeid( first ), typeid( second ) ) ) );
        assert( !( is( typeid( second ), typeid( first ) ) ) ); // assersion fails!
    }
    am I missing something here?
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    before() doesn't indicate which class comes before another in an inheritance hierarchy, it indicates a consistent ordering of classes that in your example appears to follow the order of the class definitions in your file. Right?

  3. #3
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,636
    how then do we use type_info to give us this information? I can't use dynamic_cast, either. do I need to make my own RTTI system...?
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    I have no idea. The Boost Interface Library?

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    I don't trust RTTI functions (other than dynamic_cast). I tried using typeid() a few times before and it never worked that way I wanted or expected. I'm guessing type_info is just as unreliable as typeid().

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,636
    >> I have no idea. The Boost Interface Library?

    hmm...I was hoping there was a straightforward way to do this with C++ abi facilities.

    >> I'm guessing type_info is just as unreliable as typeid().

    typeid actually returns a reference to a typeinfo structure. you can't have one without the other. but yeah, what it boils down to is that the C++ RTTI is basically useless...
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  7. #7
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I don't think it is really unreliable (unless you make assumptions that compiler-specific things work the same everywhere), but apparently here it won't do what you need (at least before is meant for something different).

    What do you want to achieve here and why?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    If you're talking about types and metaprogramming, Boost.TypeTraits has an is_base_and_derived metafunction.

    Given runtime parameters, you can use dynamic_cast to find out if a pointer/reference is of a type or one of its subtype.

    But typeid is useful only for identity and equality.

    What exactly are you trying to do?
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  9. #9
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,636
    >> If you're talking about types and metaprogramming, Boost.TypeTraits has an is_base_and_derived metafunction. Given runtime parameters, you can use dynamic_cast to find out if a pointer/reference is of a type or one of its subtype.

    unfortunately, for that to work I need to have access to the complete type, which I don't.

    basically I have something like this:

    Code:
    struct alarm
    {
        alarm( void )
        {
            classify( this );
        }
     
        template < typename Alarm >
        static
        void
        classify( Alarm * self )
        {
            self->type = &typeid( Alarm );
        }
     
        virtual
        ~alarm( void )
        {   }
     
        std::type_info const
            * type;
    };
     
    struct perimeter_alarm : alarm
    {
        perimeter_alarm( void )
        {
            classify( this );
        }
    };
     
    struct intrusion_alarm : perimeter_alarm
    {
        intrusion_alarm( void )
        {
            classify( this );
        }
    };
     
    struct fire_alarm : perimeter_alarm
    {
        fire_alarm( void )
        {
            classify( this );
        }
    };
     
    // typedef functor< void ( * ) ( alarm & ) > handler;
     
    typedef void ( * handler ) ( alarm & );
     
    struct node
    {
        template< typename Alarm >
        void
        attach( handler const & )
        {
        /*
            associate typeid with a handler
        */
        }
     
        void
        handle( alarm & )
        {
        /*
            compare stored typeid for the alarm
            and invoke appropriate handlers
        */
        }
    };
     
    void
    logger( alarm & )
    {   }
     
    void
    sprinkler( alarm & )
    {   }
     
    void
    contact_authorities( alarm & )
    {   }
     
    int
    main( void )
    {
        node
            controller;
        controller.attach< fire_alarm >( sprinkler );
        controller.attach< intrusion_alarm >( contact_authorities );
        controller.attach< alarm >( logger );
    }
    before I was using a system where I defined a constant id for each type. very labor intensive and limited in that it only matched exact id's. so if I wanted to install a handler for 'perimeter_alarm' I would have to associate it with that class and every class that derived from it. I just wanted something more simple and manageable...
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    OK, so for attach< cls >( fn ), you want fn to be called for all alarms of type cls or any subclass.

    How about something like this?
    Code:
    class node
    {
      class dispatcher_base
      {
      public:
        virtual void dispatch(alarm &a) = 0;
        virtual ~dispatcher_base() {}
      };
      template <typename Alarm>
      class dispatcher
      {
        std::tr1::function<void (Alarm&)> handler;
      public:
        dispatcher(const std::tr1::function<void (Alarm&)> ah) : handler(ah) {}
        void dispatch(alarm &a) {
          if(Alarm *p = dynamic_cast<Alarm*>(&a)) {
            handler(*p);
          }
        }
      };
    
      boost::ptr_vector<dispatcher_base> dispatchers;
    
    public:
      template <typename Alarm>
      void attach(std::tr1::function<void (Alarm&)> handler)
      {
        dispatchers.push_back(new dispatcher<Alarm>(handler));
      }
    
      void handle(alarm &a)
      {
        std::for_each(dispatchers.begin(), dispatchers.end(),
          std::tr1::bind(&dispatcher_base::dispatch, _1, a));
      }
    };
    This works the way you want. The obvious drawback is that there is a virtual call for every installed handler, whether it actually handles the relevant alarm or not. No log(N) lookup of handlers anymore, it is now linear. There's a few additional allocations. On the plus side, you preserve full type info, to the point of letting the handler functions use the original alarm type as the argument.

    Essentially, my solution is a bit of sugar coating for installing all handlers for the base alarm type and doing the dynamic_cast test in the handler body.



    A more advanced solution should be possible, but is probably very complicated. Upon registering a handler, it ought to be possible to automatically register the alarm class too and determine its place in the hierarchy. But I haven't looked deeply enough into metaprogramming to say for sure, and that's saying something.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,636
    >> Upon registering a handler, it ought to be possible to automatically register the alarm class too and determine its place in the hierarchy.

    I'm not sure I know what you mean. but for these purposes you're solution works perfectly. thank you.

    >> The obvious drawback is that there is a virtual call for every installed handler, whether it actually handles the relevant alarm or not.

    a small price to pay.
    Last edited by Sebastiani; 03-01-2008 at 08:00 PM.
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,636

    update

    interesting. as it turns out, with just slight modification this becomes a truly dynamic dispatch mechanism:

    Code:
     
    struct alarm
    {
             virtual
             ~alarm( void )
             {          }
    };
     
    struct perimeter_alarm : alarm {          };
     
    struct intrusion_alarm : perimeter_alarm {          };
     
    struct fire_alarm : perimeter_alarm {          };
     
    struct alarm_dispatcher_base
    {
             virtual
             void
             handle( alarm & alarm ) = 0;
     
             virtual
             ~alarm_dispatcher_base( void )
             {          }
    }; 
     
    template < typename Alarm, typename Handler > 
    struct alarm_dispatcher : alarm_dispatcher_base
    {
             alarm_dispatcher( Handler handler )
             : handler( handler )
             {          }          
     
             virtual
             void
             handle( alarm & alarm )
             {
                         Alarm * ptr = dynamic_cast< Alarm * >( &alarm );
                         if( ptr )
                                     handler( *ptr );             
             }    
     
             Handler
                         handler;
    }; 
     
    struct node
    {
             typedef
             std::list< boost::shared_ptr< alarm_dispatcher_base > > 
                       handler_table;
     
             template< typename Alarm, typename Handler >
             void
             attach( Handler handler )
             {
                         table.push_back( new alarm_dispatcher< Alarm, Handler >( handler ) );
             }
     
             void
             handle( alarm & alarm )
             {
                         for( handler_table::iterator seq = table.begin( ), fin = table.end( ); seq != fin; ++seq )
                                     ( *seq )->handle( alarm );
             }
     
             handler_table
                         table;    
    };
     
    void
    logger( alarm & )
    {          }
     
    void
    sprinkler( fire_alarm & )
    {          }
     
    void
    contact_authorities( intrusion_alarm & )
    {          }
     
    int
    main( void )
    {
             node
                         controller;
             controller.attach< fire_alarm >( sprinkler );
             controller.attach< intrusion_alarm >( contact_authorities );
             controller.attach< alarm >( logger );      
             fire_alarm
                         fire;
             controller.handle( fire );
    }
    thanks again to CornedBee for the excellent suggestion!

    - cheers
    Code:
    if( numeric_limits< byte >::digits != bits_per_byte )
        error( "program requires bits_per_byte-bit bytes" );
    24bbs.cpp

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. srand() Clarification
    By Epo in forum C++ Programming
    Replies: 2
    Last Post: 03-03-2005, 10:05 PM
  2. Need a clarification here
    By bithub in forum A Brief History of Cprogramming.com
    Replies: 30
    Last Post: 12-27-2004, 12:06 AM
  3. exercise clarification truth table
    By curlious in forum C++ Programming
    Replies: 1
    Last Post: 12-18-2003, 06:28 PM
  4. A little clarification?
    By Dr Nick in forum C++ Programming
    Replies: 2
    Last Post: 06-20-2002, 01:47 PM
  5. Clarification of Function Templates
    By biosx in forum C++ Programming
    Replies: 2
    Last Post: 02-20-2002, 10:42 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21