Meringkas Pola Pengunjung (C ++)

Kekurangan dari implementasi tipikal

Artikel tersebut sengaja tidak memberikan contoh penerapan umum pola pengunjung di C ++.





Jika Anda tidak terbiasa dengan pola ini, Anda dapat membiasakan diri dengannya di sini .





Singkatnya, pola ini sangat berguna jika Anda perlu melintasi kumpulan pointer ke kelas dasar abstrak, menerapkan beberapa jenis operasi padanya tergantung pada jenis yang tersembunyi di balik abstraksi.





Oleh karena itu, mari langsung ke kekurangan yang ingin kita hilangkan.





  • ( ), . ( - , .)





  • , , . - visit ( , - ). - visit .





  • .





?

  • , - , dynamic_cast static_cast .





  • , .





  • .





.





Source:
template< class T >
struct AbstractVisitor
{
    virtual ~AbstractVisitor() = default;
    virtual void visit( T& ) = 0;
};
      
      







(: - visit , AbstractVisitor .. T , )





. .





TypeList AbstractVisitors. AbstractVisitors , .





Source:
template< class ... T >
struct TypeList
{

};

template< class T >
struct AbstractVisitor
{
    virtual ~AbstractVisitor() = default;
    virtual void visit( T& ) = 0;
};

template< class ...T >
struct AbstractVisitors;

template< class ... T >
struct AbstractVisitors< TypeList< T... > > : AbstractVisitor< T >...
{
};
      
      







.. , ( , ). Dispatcher.





Source:
template< class Functor, class ... T >
struct Dispatcher;

template< class Functor, class ... T >
struct Dispatcher< Functor, TypeList< T... > > : AbstractVisitors< TypeList< T... > >
{
    Dispatcher( Functor functor ) : functor( functor ) {}

    Functor functor;
};
      
      







- visit.





Resolver, . Dispatcher Resolver-.





, (CRTP) Dispatcher Resolver.





( CRTP ).





Source:
template< class Dispatcher, class T >
struct Resolver : AbstractVisitor< T >
{
    void visit( T& obj ) override 
    {
        static_cast< Dispatcher* >( this )->functor( obj );
    };
};

template< class Functor, class ... T >
struct Dispatcher< Functor, TypeList< T... > > : AbstractVisitors< TypeList< T... > >, Resolver< Dispatcher< Functor, TypeList< T... > >, T >...
{
    Dispatcher( Functor functor ) : functor( functor ) {}

    Functor functor;
};
      
      







.





Dispatcher. , Dispatcher , ?





, Resolver, Dispatcher .





, AbstractVisitor< T >.( .)





Source:
template< class ... T >
struct AbstractVisitors< TypeList< T... > > : virtual AbstractVisitor< T >...
{
};

template< class Dispatcher, class T >
struct Resolver : virtual AbstractVisitor< T >
{
    void visit( T& obj ) override 
    {
        static_cast< Dispatcher* >( this )->functor( obj );
    };
};
      
      







(AbstractObject) - (Object1, Object2), .





test test, .





:





Source:
struct Object1;
struct Object2;

using ObjectList = TypeList< Object1, Object2 >;

struct AbstractObject
{
    virtual void accept( AbstractVisitors< ObjectList >& visitor ) = 0; 
};

struct Object1 : AbstractObject
{
    void accept( AbstractVisitors< ObjectList >& visitor ) override 
    { 
        static_cast< AbstractVisitor< Object1 >& >( visitor ).visit( *this );  
    };
};

struct Object2 : AbstractObject
{
    void accept( AbstractVisitors< ObjectList >& visitor ) override 
    { 
        static_cast< AbstractVisitor< Object2 >& >( visitor ).visit( *this );
    };
};

void test( Object1& obj )
{
    std::cout << "1" << std::endl;
}

template< class T >
void test( T& obj )
{
    std::cout << "2" << std::endl;
}

int main()
{
    Object1 t1,t2,t3,t4;
    Object2 e1,e2,e3;

    std::vector< AbstractObject* > vector = { &t1, &e1, &t2, &t3, &e2, &e3, &t4 };
		
    auto l = []( auto& obj ){ test(obj); };
    Dispatcher<decltype(l), ObjectList> dispatcher;
  
    for( auto* obj : vector )
    {
        obj->accept( dispatcher );
    }
}
      
      







(: visitor.visit( *this )



, , .)





Dispatcher - , .





, - accept AbstractObject, Object1 Object2, .. , .





Dispatchable. C - accept - . Dispatcher.





DISPATCHED, - accept Object1 Object2.





Source:
template< class TypeList >
struct Dispatchable
{
    virtual ~Dispatchable() = default;
    virtual void accept( AbstractVisitors< TypeList >& ) = 0;

    template< class Functor >
    void dispatch( Functor functor )
    {
        static Dispatcher< decltype(functor), TypeList > dispatcher( functor );
        accept( dispatcher );
    };
};

#define DISPATCHED( TYPE, TYPE_LIST ) \
    void accept( AbstractVisitors< TYPE_LIST >& visitor ) override \
    { \
        static_cast< AbstractVisitor< TYPE >& >( visitor ).visit( *this );  \
    }
      
      











AbstractObject Dispatchable. Object1 Object2 DISPATCHED.





Source:

struct Object1;
struct Object2;

using ObjectList = TypeList< Object1, Object2 >;

struct AbstractObject : Dispatchable< ObjectList >
{
};

struct Object1 : AbstractObject
{
    DISPATCHED( Object1, ObjectList )
};

struct Object2 : AbstractObject
{
    DISPATCHED( Object2, ObjectList )
};

      
      







, - accept . .





:





Source:
void test( Object1& obj )
{
    std::cout << "1" << std::endl;
}

template< class T >
void test( T& obj )
{
    std::cout << "2" << std::endl;
}

int main()
{
    Object1 t1,t2,t3,t4;
    Object2 e1,e2,e3;

    std::vector< AbstractObject* > vector = { &t1, &e1, &t2, &t3, &e2, &e3, &t4 };

    for( auto* obj : vector )
    {
        obj->dispatch( []( auto& obj ) { test(obj); } );
    }
}
      
      











Output:

1





2





1





1





2





2





1





  • , , .





  • , .. .





  • Kita dapat memanfaatkan template fungsi sepenuhnya.





  • Tetap mungkin untuk menggunakan implementasi biasa dari pengunjung, itu cukup hanya membuat pewaris Anda dari AbstractVisitors dan meneruskannya ke fungsi terima .









Apa kerugiannya?





  • Tipuan tambahan, sejak Dispatcher berisi functor.









Tautan ke kode di penjelajah kompiler.





Sumber lengkap:
#include <type_traits>
#include <iostream>
#include <vector>

template< class ... T >
struct TypeList
{

};

template< class T >
struct AbstractVisitor
{
    virtual ~AbstractVisitor() = default;
    virtual void visit( T& ) = 0;
};

template< class ...T >
struct AbstractVisitors;

template< class ... T >
struct AbstractVisitors< TypeList< T... > > : virtual AbstractVisitor< T >...
{
};

template< class Dispatcher, class T >
struct Resolver : virtual AbstractVisitor< T >
{
    void visit( T& obj ) override 
    {
        static_cast< Dispatcher* >( this )->functor( obj );
    };
};

template< class Functor, class ... T >
struct Dispatcher;

template< class Functor, class ... T >
struct Dispatcher< Functor, TypeList< T... > > : AbstractVisitors< TypeList< T... > >, Resolver< Dispatcher< Functor, TypeList< T... > >, T >...
{
    Dispatcher( Functor functor ) : functor( functor ) {}

    Functor functor;
};

template< class TypeList >
struct Dispatchable
{
    virtual ~Dispatchable() = default;
    virtual void accept( AbstractVisitors< TypeList >& ) = 0;

    template< class Functor >
    void dispatch( Functor functor )
    {
        static Dispatcher< decltype(functor), TypeList > dispatcher( functor );
        accept( dispatcher );
    };
};

#define DISPATCHED( TYPE, TYPE_LIST ) \
    void accept( AbstractVisitors< TYPE_LIST >& visitor ) override \
    { \
        static_cast< AbstractVisitor< TYPE >& >( visitor ).visit( *this );  \
    }

struct Object1;
struct Object2;

using ObjectList = TypeList< Object1, Object2 >;

struct AbstractObject : Dispatchable< ObjectList >
{
};

struct Object1 : AbstractObject
{
    DISPATCHED( Object1, ObjectList )
};

struct Object2 : AbstractObject
{
    DISPATCHED( Object2, ObjectList )
};

void test( Object1& obj )
{
    std::cout << "1" << std::endl;
}

template< class T >
void test( T& obj )
{
    std::cout << "2" << std::endl;
}

int main()
{
    Object1 t1,t2,t3,t4;
    Object2 e1,e2,e3;

    std::vector< AbstractObject* > vector = { &t1, &e1, &t2, &t3, &e2, &e3, &t4 };

    for( auto* obj : vector )
    {
        obj->dispatch( []( auto& obj ) { test(obj); } );
    }
}
      
      














All Articles