Eliminate second invocation of class (example_visitor) object

M

Mark

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();
}
 
I

Ike Naar

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();
}
}
 
M

Mark

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
 
I

Ike Naar

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?
 
M

Mark

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?
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top