Eliminate second invocation of class (example_visitor) object

Discussion in 'C++' started by Mark, Jun 29, 2013.

  1. Mark

    Mark Guest

    Code referenced below compiles and runs. The issue I'm faced with is the constructor for example_visitor is invoked twice. The second invocation of the example_visitor constructor is predicated on invocation of dispatch in particular the line: typename Type::value_type visitor ; within dispatch

    What modifications needs to occur such that I could use the 'this' pointer from the first instance of example_visitor in dispatch? I tried modifying the code to have example_visitor derive off dispatch but to no avail.

    Sample appreciated. Thanks in advance.


    # include <map>
    # include <boost/variant.hpp>
    # include <boost/mpl/vector.hpp>
    # include <boost/mpl/contains.hpp>
    # include <boost/utility/enable_if.hpp>
    # include <boost/lexical_cast.hpp>
    # include <boost/variant.hpp>
    # include <boost/any.hpp>
    # include <boost/shared_ptr.hpp>

    # include <vector>
    # include <string>
    # include <iostream>

    // Generic visitor
    template <typename Visitor, typename TypeList>
    struct generic_visitor :
    public boost::static_visitor<void>,
    public Visitor
    {
    template <typename T>
    inline void operator ()
    ( T& v, typename boost::enable_if<
    typename boost::mpl::contains< TypeList, T >::type >::type *dummy= NULL )
    {
    Visitor::eek:perator () (v);
    }

    template <typename T>
    inline void operator ()
    ( T& v,
    typename boost::disable_if <
    typename boost::mpl::contains< TypeList, T >::type >::type *dummy = NULL )
    {}
    };

    class nil {
    protected :
    nil(const nil& );
    nil& operator = (const nil& ) ;
    unsigned int abc ;
    public :
    unsigned int const get() { return abc ; }
    nil ()
    : abc ( 5 )
    {}
    };

    template < typename Type >
    class dispatch {

    typedef boost::variant <
    nil&, char&, int&, double&
    > sql_field;

    typename Type::value_type visitor ;

    private :
    int test_int ;
    double test_double ;

    public :
    dispatch ()
    : test_int ( 1 )
    , test_double ( 1. )
    {}

    template < typename T >
    void doit ( T& in ) {
    std::cout << "(typeid=" << typeid( in ).name() << std::endl;
    typename dispatch< Type >::sql_field obj ( in );
    boost::apply_visitor ( this->visitor, obj );
    }

    };

    struct example_visitor
    {
    typedef generic_visitor
    < example_visitor,
    boost::mpl::vector<nil, char, int > > value_type;
    typedef dispatch < example_visitor > dispatch_evisit ;


    dispatch_evisit* ptr ;
    int x ;
    nil n ;

    example_visitor()
    : ptr ( 0 )
    , x ( 4 )
    { std::cout << "." ; }

    void operator () (char& v) {
    std::cout << "character detected" << std::endl;
    }

    void operator () (int& v) {
    std::cout << "(integer detected=" << v << std::endl;
    }

    void operator () (nil& v) {
    std::cout << "nil detected=" << v.get() << std::endl;
    }
    void initialize () {
    ptr = new dispatch_evisit ;
    }
    void execute () {
    if ( ptr ) {
    ptr->doit ( x ) ;
    ptr->doit ( n ) ;
    x += 2 ;
    }
    }
    };


    int main() {

    example_visitor test;
    test.initialize();
    for ( unsigned int odx ( 0 ); odx < 10; ++odx ) {
    test.execute() ;
    }
    std::cin.get();
    }
     
    Mark, Jun 29, 2013
    #1
    1. Advertising

  2. Mark

    Ike Naar Guest

    On 2013-06-29, Mark <> wrote:
    > Code referenced below compiles and runs. The issue I'm faced with is
    > the constructor for example_visitor is invoked twice. The second
    > invocation of the example_visitor constructor is predicated on
    > invocation of dispatch in particular the line: typename
    > Type::value_type visitor ; within dispatch
    >
    > What modifications needs to occur such that I could use the 'this'
    > pointer from the first instance of example_visitor in dispatch?
    > I tried modifying the code to have example_visitor derive off
    > dispatch but to no avail.


    Instead of letting generic_visitor derive from Visitor,
    let it contain a pointer to its Visitor; you'll need to
    add a extra constructor for dispatch and generic_visitor
    in order to initialize this pointer.

    > Sample appreciated.


    # include <boost/variant.hpp>
    # include <boost/mpl/vector.hpp>
    # include <boost/mpl/contains.hpp>
    # include <boost/utility/enable_if.hpp>
    # include <iostream>

    template <typename Visitor, typename TypeList>
    struct generic_visitor :
    public boost::static_visitor<void>
    {
    Visitor *myvisitor;
    generic_visitor(Visitor *v) : myvisitor(v) {}

    template <typename T>
    inline void operator()
    ( T& v, typename boost::enable_if<
    typename boost::mpl::contains<TypeList, T>::type>::type* = NULL)
    {
    (*myvisitor)(v);
    }

    template <typename T>
    inline void operator() (T&,
    typename boost::disable_if<
    typename boost::mpl::contains<TypeList, T>::type>::type* = NULL)
    {}
    };

    class nil {
    private :
    unsigned int abc;
    public :
    unsigned int get() {return abc;}
    nil() : abc(5) {}
    };

    template <typename Type>
    class dispatch
    {
    generic_visitor<Type, boost::mpl::vector<nil, char, int> > visitor;

    public :
    dispatch(Type *v) : visitor(v) {}
    template < typename T >
    void doit ( T& in ) {
    std::cout << "(typeid=" << typeid(in).name() << std::endl;
    boost::variant<nil&, char&, int&, double&> obj = in;
    boost::apply_visitor(visitor, obj);
    }
    };

    struct example_visitor
    {
    dispatch<example_visitor> *ptr;
    int x;
    nil n;

    example_visitor() : ptr(0), x(4)
    {
    std::cout << "[example_visitor:ctor]";
    }

    void operator()(char&) {
    std::cout << "character detected\n";
    }

    void operator()(int& v) {
    std::cout << "integer detected=" << v << std::endl;
    }

    void operator()(nil& v) {
    std::cout << "nil detected=" << v.get() << std::endl;
    }
    void initialize()
    {
    ptr = new dispatch<example_visitor>(this);
    }
    void execute()
    {
    if (ptr) {
    ptr->doit(x);
    ptr->doit(n);
    x += 2;
    }
    }
    };

    int main()
    {
    example_visitor test;
    test.initialize();
    for (unsigned int odx = 0; odx != 10; ++odx) {
    test.execute();
    }
    }
     
    Ike Naar, Jun 30, 2013
    #2
    1. Advertising

  3. Mark

    Mark Guest

    On Sunday, June 30, 2013 4:02:13 AM UTC-4, Ike Naar wrote:

    >
    > Instead of letting generic_visitor derive from Visitor,
    >
    > let it contain a pointer to its Visitor; you'll need to
    >
    > add a extra constructor for dispatch and generic_visitor
    >
    > in order to initialize this pointer.
    >



    Thanks for the suggestion. Trouble is I loose the option to control typelist. For instance the following no longer compiles. Note: void operator( nil& v ) is missing :

    struct example_visitor
    {
    dispatch<example_visitor> *ptr;
    int x ;
    nil n ;

    example_visitor()
    : ptr ( 0 )
    , x ( 4 )
    { std::cout << "." ; }

    void operator () (char& v) {
    std::cout << "character detected" << std::endl;
    }

    void operator () (int& v) {
    std::cout << "(integer detected=" << v << std::endl;
    }

    void initialize () {
    ptr = new dispatch<example_visitor>(this);
    }
    void execute () {
    if ( ptr ) {
    ptr->doit ( x ) ;
    //ptr->doit ( n ) ;
    x += 2 ;
    }
    }
    };

    With my initial version I could do:
    typedef lets_see
    < example_visitor,
    boost::mpl::vector<nil, char, int > > value_type;

    or

    typedef lets_see
    < example_visitor,
    boost::mpl::vector< char, int > > value_type;

    or ...

    Thoughts

    Thanks
     
    Mark, Jul 1, 2013
    #3
  4. Mark

    Ike Naar Guest

    On 2013-07-01, Mark <> wrote:
    > On Sunday, June 30, 2013 4:02:13 AM UTC-4, Ike Naar wrote:
    >
    >>
    >> Instead of letting generic_visitor derive from Visitor,
    >>
    >> let it contain a pointer to its Visitor; you'll need to
    >>
    >> add a extra constructor for dispatch and generic_visitor
    >>
    >> in order to initialize this pointer.
    >>

    >
    >
    > Thanks for the suggestion. Trouble is I loose the option to control
    > typelist. For instance the following no longer compiles.
    > Note: void operator( nil& v ) is missing :
    >
    > struct example_visitor
    > {
    > dispatch<example_visitor> *ptr;
    > int x ;
    > nil n ;
    >
    > example_visitor()
    > : ptr ( 0 )
    > , x ( 4 )
    > { std::cout << "." ; }
    >
    > void operator () (char& v) {
    > std::cout << "character detected" << std::endl;
    > }
    >
    > void operator () (int& v) {
    > std::cout << "(integer detected=" << v << std::endl;
    > }
    >
    > void initialize () {
    > ptr = new dispatch<example_visitor>(this);
    > }
    > void execute () {
    > if ( ptr ) {
    > ptr->doit ( x ) ;
    > //ptr->doit ( n ) ;
    > x += 2 ;
    > }
    > }
    > };
    >
    > With my initial version I could do:
    > typedef lets_see
    > < example_visitor,
    > boost::mpl::vector<nil, char, int > > value_type;
    >
    > or
    >
    > typedef lets_see
    > < example_visitor,
    > boost::mpl::vector< char, int > > value_type;
    >
    > or ...
    >
    > Thoughts


    You say your example "no longer compiles", but the example is incomplete.
    If I complete it by adding dummy classes for the missing types, it does
    compile.
    Can you please post a complete example?
     
    Ike Naar, Jul 1, 2013
    #4
  5. Mark

    Mark Guest

    On Monday, July 1, 2013 1:34:50 AM UTC-4, Ike Naar wrote:

    >
    > > You say your example "no longer compiles", but the example is incomplete.

    >
    > If I complete it by adding dummy classes for the missing types, it does
    >
    > compile.
    >
    > Can you please post a complete example?


    I think the issue is I didn't express myself properly in my initial post. My aim is to allow client code to be able to create a subsets of the variant types. So given a complete list of variant types, more specifically (original code):


    typedef boost::variant <
    nil&, char&, int&, double&
    > sql_field;



    For discussion purposes assume client's class is 'example_visitor'. Client should be able to do:

    typedef lets_see
    < example_visitor,
    boost::mpl::vector<nil, char, int > > value_type; //complete list

    or

    typedef lets_see
    < example_visitor,
    boost::mpl::vector< char, int > > value_type; //subset

    or
    typedef lets_see
    < example_visitor,
    boost::mpl::vector< int > > value_type; //subset

    etc

    To achieve my objective, I used boost::enable_if/disable_if. In doing so the Client only needs to specify the operator for the subset.


    struct example_visitor
    {
    typedef lets_see
    < example_visitor,
    boost::mpl::vector< int > > value_type;

    typedef dispatch < example_visitor > dispatch_evisit ;
    dispatch_evisit* ptr ;
    int x ;
    nil n ;

    example_visitor()
    : ptr ( 0 )
    , x ( 4 )
    {}

    inline void operator () (int& v) {
    std::cout << "(integer detected=" << v << std::endl;
    }

    void initialize () {
    ptr = new dispatch_evisit;
    }
    void execute () {
    if ( ptr ) {
    ptr->doit ( x ) ;
    //since nil is not part of the typelist nil goes through disable_if
    ptr->doit ( n ) ;
    x += 2 ;
    }
    }
    };

    With your version client is no longer able to specify a subset of variant types. Makes sense?
     
    Mark, Jul 1, 2013
    #5
  6. Mark

    Mark Guest

    On Monday, July 1, 2013 9:23:11 AM UTC-4, Mark wrote:

    > With your version client is no longer able to specify a subset of variant types. Makes sense?


    Found a solution. Thanks for your help
     
    Mark, Jul 1, 2013
    #6
  7. Mark

    Ike Naar Guest

    On 2013-07-01, Mark <> wrote:
    > On Monday, July 1, 2013 9:23:11 AM UTC-4, Mark wrote:
    >
    >> With your version client is no longer able to specify a subset of variant types. Makes sense?

    > Found a solution. Thanks for your help


    Do you want to share it?
     
    Ike Naar, Jul 1, 2013
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. E11
    Replies:
    1
    Views:
    4,781
    Thomas Weidenfeller
    Oct 12, 2005
  2. benben
    Replies:
    1
    Views:
    411
    Alf P. Steinbach
    Feb 15, 2006
  3. Steve Conover
    Replies:
    9
    Views:
    173
    Steve Conover
    May 9, 2006
  4. Sebastian
    Replies:
    2
    Views:
    477
    Sebastian
    Feb 8, 2012
  5. yelipolok
    Replies:
    4
    Views:
    263
    John W. Krahn
    Jan 27, 2010
Loading...

Share This Page