home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 33,271 of 33,346   
   Alf P. Steinbach to Ryan   
   Re: Possible Tag Dispatching   
   15 Jan 14 05:02:56   
   
   From: alf.p.steinbach+usenet@googlemail.com   
      
   On 15.01.2014 01:47, Ryan wrote:   
   > I've included the below code in what I believe is the hard way of doing   
   > things.  Structure A has the information on the structure type being   
   > stored.  It could be either a C, D or E structure.   
      
   I assume that means that an "A" object stores an object that can be   
   either a C, a D or an E.   
      
      
   >  If you notice the   
   > switch statement, though, I really don't care what type it being   
   > returned.  They all use the same add method.  Is there a way 'getType'   
   > can return a type for tag dispatching that would allow the getC, getD   
   > and getE to become a templated method based on a type trait?   
      
   It's easy enough to generalize getC(), getD() and getD() as a single   
   member function template, using e.g. dynamic_cast.   
      
   A getType function is not needed for that, nor is some type traits class   
   needed.   
      
   I assume that it's OK to just get the function template even if it   
   doesn't involve getType or some type trait.   
      
      
   >  This way   
   > the switch statement can be eliminated and the simple 'add' called.   
      
   I assume that you want the ability to call a general `add` function, and   
   have it routed to or applied with the stored object of unknown type.   
      
      
   > #include    
   > enum eType { cc, dd, ee };   
   >   
   > struct B {};   
   > struct C {};   
   > struct D {};   
   > struct E {};   
   >   
   > struct A {   
   >     eType getType(void) { return dd; }   
   >     C getC(void) { return C(); }   
   >     D getD(void) { return D(); }   
   >     E getE(void) { return E(); }   
   > };   
   > void add(int num, B b, C c) { std::cout << "Added C" << std::endl; }   
   > void add(int num, B b, D d) { std::cout << "Added D" << std::endl; }   
   > void add(int num, B b, E e) { std::cout << "Added E" << std::endl; }   
   >   
   > int main() {   A a;   
   >     switch(a.getType()) {   
   >       case cc: add(3, B(), a.getC());  break;   
   >       case dd: add(4, B(), a.getD());  break;   
   >       case ee: add(5, B(), a.getE());  break;   
   >       default:   
   >         std::cout << "Problem" << std::endl;   
   >         break;   
   >     }   
   >   
   >     return 0;   
   > }   
      
      
   Hopefully the following captures your requirements, but it's not clear   
   what aspects of the original code are requirements and what aspects are   
   simply artifacts of a particular attempt to implement the requirements.   
      
      
   [code]   
   #ifndef CPPX_IS_DELETED   
   #   define CPPX_IS_DELETED  = delete   
   #endif   
      
   #include    
   #include            // std::unique_ptr   
   #include           // std::move   
   using namespace std;   
      
   struct B {};   
      
   struct Stored_object   
   {   
        virtual void add( B ) = 0;   
   };   
      
   struct C: Stored_object   
   {   
        void add( B ) override { cout << "Added C" << endl; }   
   };   
      
   struct D: Stored_object   
   {   
        void add( B ) override { cout << "Added D" << endl; }   
   };   
      
   struct E: Stored_object   
   {   
        void add( B ) override { cout << "Added E" << endl; }   
   };   
      
   class A   
   {   
   private:   
        unique_ptr   stored_object_;   
      
        A( A const& ) CPPX_IS_DELETED;   
        A& operator=( A const& ) CPPX_IS_DELETED;   
      
   public:   
        auto stored_object()   
            -> Stored_object&   
        { return *stored_object_; }   
      
        template< class Stored >   
        auto stored()   
            -> Stored&   
        { return dynamic_cast( *stored_object_ ); }   
      
        A( C o ): stored_object_( new C( move( o ) ) ) {}   
        A( D o ): stored_object_( new D( move( o ) ) ) {}   
        A( E o ): stored_object_( new E( move( o ) ) ) {}   
   };   
      
   auto main()   
       -> int   
   {   
        C c;   
        A a( c );   
      
      
        a.stored_object().add( B() );   
      
        (void) a.stored();      // Does not throw.   
        cout << "Attempting to access stored object as a `D`..." << endl;   
        try   
        {   
            a.stored();      // Throws! As it should.   
        }   
        catch( exception const& x )   
        {   
            cerr << "! " << x.what() << endl;   
        }   
   }   
   [/code]   
      
      
   If you want A::stored to return a copy, or reference to const, just   
   modify the result type (and in the latter case possibly make also the   
   member function const).   
      
      
   Cheers & hth.,   
      
   - Alf   
      
   PS:   
   Norwegian/Scandinavian readers: I'm looking for a job since I'm now   
   almost recovered from surgery over the last year and a half (just a   
   little bit more surgery now at the end of the month) . Pro hiring me:   
   I'm pretty good. Con: age. I'm a moderator of this group, and I was   
   awarded Microsoft MVP in 2012. Your firm just may be able to catch me.   
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca