Jeroen and Noah Roberts, doing reflection in C++

J

John Harrison

Jeroen recently asked a question where he was trying to put arbitary
types onto a list and then do something useful with them afterwards.

Not possible I said, in my usual tetchy manner.

Noah Roberts then pointed me to the boost::any type.

Makes no difference I said.

Well having thought about it, I've changed my mind. The following code
allows a library user to put values of arbitary types onto a list, and
then print them out afterwards. Obviously the user must provide a
function to do the printing. This is done by specialising a function
template provided by the library.

Here's the code, comments welcome. This is a new technique to me.

// library.h
#ifndef LIBRARY_H
#define LIBRARY_H

#include <boost/any.hpp>
#include <list>
#include <map>
#include <typeinfo>
#include <functional>

struct typeinfo_lessthan : public std::binary_function<const
std::type_info*, const std::type_info*, bool>
{
bool operator()(const std::type_info* x, const std::type_info* y) const
{
/* dinkumware implementation of typeinfo::before returns int for some
reason */
return x->before(*y) != 0;
}
};

typedef std::list<boost::any> value_list_type;
typedef std::map<const std::type_info*, void (*)(boost::any),
typeinfo_lessthan> method_map_type;

extern value_list_type value_list;
extern method_map_type print_map;

template <class T>
void print(boost::any);

template <class T>
void add_to_list(const T& value)
{
boost::any any_value(value);
value_list.push_back(any_value);
print_map[&typeid(T)] = print<T>;
}

inline void print_value(boost::any value)
{
(*print_map[&value.type()])(value);
}

#endif

// main.cpp
#include <iostream>
#include <vector>
#include "library.h"

template <>
void print<int>(boost::any x)
{
std::cout << "int=" << *boost::any_cast<int>(&x) << '\n';
}

template <>
void print<double>(boost::any x)
{
std::cout << "double=" << *boost::any_cast<double>(&x) << '\n';
}

template <>
void print< std::vector<int> >(boost::any x)
{
std::vector<int>& v = *boost::any_cast< std::vector<int> >(&x);
std::cout << "vector=";
for (std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++i)
std::cout << *i << ' ';
std::cout << '\n';
}

int main()
{
add_to_list(1);
add_to_list(2.0);
std::vector<int> v(4, 3);
add_to_list(v);
for (value_list_type::const_iterator i = value_list.begin(); i !=
value_list.end(); ++i)
{
print_value(*i);
}
}

john
 
J

John Harrison

Thinking about it a little more the library could provide a default
implementation of the print routine, like this


template <class T>
void print(boost::any x)
{
std::cout << x.type().name() << '=' << *boost::any_cast<T>(&x) << '\n';
}

This would mean the specialisations for int and double of this function
in the original code could be removed.

john
 
P

Piyo

John said:
Here's the code, comments welcome. This is a new technique to me.

Welcome to the wonderful world of boost :) It's an awesome library
that should be dist'ed with EVERY single compiler and should be
taught in all classes that teach C++ :)

I learn about a new part of boost everyday myself.

My Motto:
Q: How do I do this?
A: Did you check boost first? :)

Since you just discovered any (unbound variant types) you might
want to invest some time in boost::variant (bounded variant types).
Why limit yourself to a limited set of types when any can REALLY
contain any. Well, in practical applications, the number of actual
types used in your variant type is limited. If you enumerate these,
apriori, you can add some pretty nifty functionality such as the
visitor pattern on top of it. Using any makes it difficult to
apply (not impossible) the visitor pattern whereas variant practically
gives it for free.

Good Luck with that!!
 
J

John Harrison

Piyo said:
Welcome to the wonderful world of boost :) It's an awesome library
that should be dist'ed with EVERY single compiler and should be
taught in all classes that teach C++ :)

I learn about a new part of boost everyday myself.

My Motto:
Q: How do I do this?
A: Did you check boost first? :)

Since you just discovered any (unbound variant types) you might
want to invest some time in boost::variant (bounded variant types).

I was aware of boost::any previously, it was the idea of storing
typeinfo in a map to look up an associated template function that was
new for me. In my code, within the template function print<T>, you do
have access to the type of the original value before it was placed into
boost::any. This was what I had said was impossible.
Why limit yourself to a limited set of types when any can REALLY
contain any. Well, in practical applications, the number of actual
types used in your variant type is limited. If you enumerate these,
apriori, you can add some pretty nifty functionality such as the
visitor pattern on top of it. Using any makes it difficult to
apply (not impossible) the visitor pattern whereas variant practically
gives it for free.

Good Luck with that!!

I'll have a good look at variant, looks interesting.

john
 
P

Piyo

John said:
I was aware of boost::any previously, it was the idea of storing
typeinfo in a map to look up an associated template function that was
new for me. In my code, within the template function print<T>, you do
have access to the type of the original value before it was placed into
boost::any. This was what I had said was impossible.

Sorry, my misunderstanding on what you found to be new. :)
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top