BasicFastDispatch

Help
2005-03-13
2013-04-08
  • rickappleton

    rickappleton - 2005-03-13

    I was looking for a way to do MultiMethods when I came across Loki.

    Unfortunately, I can not get StaticDispatcher to work correctly (it always switches the types of rhs and lhs around for some reason), so I decided to try the BasicFastDispatch
    In the book Modern C++ Design. However, I found there was no code snippet for this.

    So I could type it in by hand, but I'm wondering why this dispatcher has not been included in the library.

     
    • Andrei Alexandrescu

      Sorry, as of this time there is no implementation of BasicFastDispatcher in Loki. Oddly enough, I didn't even realize that until very recently when another reader has asked for it.

      I'm busy now but I had put the item on my todo list. (If anyone has it, let me know and I'll add it with due credit.)

      In the meantime, if you could post your code that displays an error in StaticDispatcher, that would be helpful.

      Andrei

       
      • rickappleton

        rickappleton - 2005-03-14

        Sorry about the other post. That is the structure for the BasicFastDispatch.

        The following is the code for the faulty StaticDispatcher:

        class CollisionExecuter
        {
        public:
          void Fire( CPlayer& p, ::Scenegraph::CModel& t );
          void OnError( ::Scenegraph::IBase& a, ::Scenegraph::IBase& b );
        };

        typedef ::Loki::StaticDispatcher
        <
          CollisionExecuter,
          ::Scenegraph::IBase,
          TYPELIST_2(CPlayer, ::Scenegraph::CModel)
        >
        CollisionDispatcher;

        Calling code:
          CPlayer *player = ...
          Scenegraph::CModel *model = ...
          CollisionExecuter exec;
          CollisionDispatcher::Go(*player, *model, exec);

        Class hierarchy:

        namespace Scenegraph
        {
        class IBase
        class IActor : public IBase
        class CModel : public IActor
        }
        class CPlayer : public Scenegraph::CModel

        Note that player and model are not pointers to the base class, but this is only a test case. When I do start to really use the MultiMethod, I will only have pointers to the base class available.

        I have tried to compile the code on Visual C++ Express Beta and gotten the following compiler error:
        error C2664: 'CollisionExecuter::Fire' : cannot convert parameter 1 from 'Scenegraph::CModel' to 'CPlayer &'

        If I switch the two parameters player and model around I get the same exact error. You'll notice that the Fire function I've provided has the arguments in CPlayer, CModel order (most derived class is first argument).

        For a test I add another Fire functions with the two arguments switched around. This gave me the following error:
        error C2666: 'CollisionExecuter::Fire' : 2 overloads have similar conversions

        Then I removed the original Fire leaving me with only
        void Fire( ::Scenegraph::CModel& t, CPlayer& p ); and still calling with CollisionDispatcher::Go(*model, *player, exec);
        This gave me the following error:
        error C2664: 'CollisionExecuter::Fire' : cannot convert parameter 2 from 'Scenegraph::CModel' to 'CPlayer &'

        This is why I concluded that somehow the lhs and rhs get mixed up. I'll see if I can test this on a different compiler today, and report back with the results.

         
        • Andrei Alexandrescu

          That's great, thanks! I set your code aside to pore over it, and I'm looking forward to hearing of any other tests you might be making.

          Andrei

           
          • rickappleton

            rickappleton - 2005-03-14

            I've tried to compiler the project on Linux now using gcc 3.3.2.

            In that case I got an error that
            void Fire(  Scenegraph::CModel&, Scengraph::CModel& ) wasn't defined.

            After adding that function it seems to compile. Seems to, because I've got a different error, not related to Loki, which I haven't been able to solve yet. Therefore I haven't been able to actually run the program to see if StaticDispatcher works correctly.

             
            • David CJ Mack

              David CJ Mack - 2008-01-11

              I have just purchased Modern C++ Design with the hopes of understanding the BasicFastDispatcher (although I don't see what's 'Basic' about it!).  Some code would really help.  The closest thing I've been able to find is the 'cooperative visitor' (http://www.artima.com/cppsource/cooperative_visitor.html) which seems to operate along similar lines.

              I'm was surprised to find that it wasn't available in the Loki library.  I'm the only one excited by it?

               
          • rickappleton

            rickappleton - 2005-03-14

            I have just tried to compile the same project using Dev-C++ 4.9.9.2 (which uses GCC 3.4.2 according to the website) and have been able to get a compiled StaticDispatcher by adding overloads for all combinations of CPlayer and CModel (4 in total).

            However, under this compiler, Loki has trouble compiling Singleton. It gives on line 105 (std::realloc), 158 (std::malloc) and 166(std::free) that these functions are not members of std. Removing std:: from these lines solves the problem. But after solving these problems, I get errors on lines 148 and 160 of SmallObj.h: abstract declarator `void*' used as declaration

             
          • rickappleton

            rickappleton - 2005-03-14

            While doing the tests with Dev-C++ I have been able to fix the errors in Visual C++ Express. This now compiles, and runs correctly.

            What I needed to do was add a Fire(CModel, CModel) overload:
            class CollisionExecuter
            {
            public:
            void Fire( CPlayer& p, ::Scenegraph::CModel& t );
            void Fire( ::Scenegraph::CModel& p, ::Scenegraph::CModel& t );
            void OnError( ::Scenegraph::IBase& a, ::Scenegraph::IBase& b );
            };

            I am not entirely sure why this was required, since I am positive that these need not be called (see the test case). But then I haven't been able to fully grasp everything in Modern C++ Design, so it is possible that these overload MUST be provided even though they are not used. Unfortunately the compiler error message isn't entirely clear on that.

            So apparently the version that works on Linux is correct. Please note that I have not yet provided overloads for Fire(CPlayer, CPlayer) but the compiler is not complaining about that.

            Thanks for the interest though and sorry to have bothered you.

             
    • rickappleton

      rickappleton - 2005-03-13

      The calling code:
        CollisionDispatcher d;
        d.Add<CPlayer, ::Scenegraph::CModel>(Fire);
        d.Go(*p, *model);

      Classes:
      class CPlayer : public Scenegraph::CModel

      namespace Scenegraph
      {
      class CModel : public IActor
      class IActor : public IBase
      class IBase
      }

       
    • Nobody/Anonymous

      Sorry my bad english... but:

      I supposed, that StticDispatcher is insensitive for TYPELIST params order (class hierarchy order), but code below demonstraits the opposite. Is it a bug &

      #include <loki\MultiMethods.h>
      #include <string>
      #include <assert.h>

      // Class hierarchy:
      class CBase { public: virtual ~CBase() {}; }; 
      class CActor : public CBase { }; 
      class CModel : public CActor {}; 
      class CPlayer : public CModel {};

      // Dispatch methods set
      class CollisionExecuter  { 
      public: 
          std::string Fire( CModel&, CModel& ) {    return "CModel-CModel"; }
          std::string Fire( CActor&, CActor& ) {    return "CActor-CActor"; } 
          std::string Fire( CPlayer&, CPlayer& ){ return "CPlayer-CPlayer";}

          std::string Fire( CPlayer&, CModel& ){    return "CPlayer-CModel";} 
          std::string Fire( CPlayer&, CActor& ){ return "CPlayer-CActor";} 

          std::string Fire( CModel&, CPlayer&){    return "CModel-CPlayer";} 
          std::string Fire( CModel&, CActor& ){    return "CModel-CActor";} 

          std::string Fire( CActor&, CPlayer&){    return "CActor-CPlayer";} 
          std::string Fire( CActor&, CModel&){    return "CActor-CModel";} 

          std::string Fire( CBase&, CBase& ) {    return "CBase-CBase"; } 
          std::string OnError( CBase&, CBase&) {    return "OnError";    } 
      }; 

      // Valid StaticDispatcher
      typedef ::Loki::StaticDispatcher
      <
      CollisionExecuter,
      CBase,
      LOKI_TYPELIST_3( CPlayer, CModel, CActor ) ,
      false,
      CBase,
      LOKI_TYPELIST_3( CPlayer, CModel, CActor ) ,
      std::string
      >
      RightDispatcher;

      // Invalid StaticDispatcher
      typedef ::Loki::StaticDispatcher
      <
      CollisionExecuter,
      CBase,
      LOKI_TYPELIST_3( CModel, CActor, CPlayer ) ,
      false,
      CBase,
      LOKI_TYPELIST_3( CModel, CActor, CPlayer ) ,
      std::string
      >
      WrongDispatcher;

      // Calling code
      void testMethod() {
          // Calling code:
          CBase *player = new CPlayer();
          CBase *model = new CModel();
          CBase *actor = new CActor();
          CollisionExecuter exec;
          // This assertions evaluates to true
          assert( "CPlayer-CModel" == RightDispatcher::Go(*player, *model, exec) );
          assert( "CActor-CModel" == RightDispatcher::Go(*actor, *model, exec));
          assert( "CModel-CModel" == RightDispatcher::Go(*model, *model, exec));
          // Assertions below fails !!!
          assert( "CPlayer-CModel" == WrongDispatcher::Go(*player, *model, exec) );
          assert( "CActor-CModel" == WrongDispatcher::Go(*actor, *model, exec));
          assert( "CModel-CModel" == WrongDispatcher::Go(*model, *model, exec));

          std::cin.get();

      }

       

Log in to post a comment.