I have several files of data which can contains different types of data. For example i can have a file of : int-int-double :
1,2,0.5
1,3,0.7
or int-char[16]-double :
1,15c48e7d3a4857bb,0.1
2,49b49e45f46aa45b,0.3
I want to build an object which can be considered as a generic reader. All i want to provide is a boost::tuple type and the object must be able to give me an appropriate regular expression to read a file using fscanf
The basic code for that object would be :
template <typename T>
class reader_t<typename T>
{
...
std::string regexp() const;
}
After that, i will instantiate an object giving the appropriate boost::tuple format.
reader_t reader<boost::tuple<int, int, double> > reader;
To read a file i would use the regexp returned by the method 'regexp' :
std::cout<<reader.regexp()<<std::endl;
In this case, it is supposed to give me:
"%d,%d,%lf\n"
I looked over the boost description but i didn't find what i needed.
Has someone an idea ?
This should get you started:
#include <cstddef>
#include <deque>
#include <string>
#include <sstream>
#include <boost/tuple/tuple.hpp>
namespace details {
struct reader_t_helper
{
typedef std::deque<std::string const*> accumulator_t;
template<typename T, int N>
struct format_accumulator
{
static void add(reader_t_helper::accumulator_t& fmts)
{
reader_t_helper::format_accumulator_impl<T, N>(fmts);
reader_t_helper::format_accumulator<T, N - 1>::add(fmts);
}
};
template<typename T>
struct format_accumulator<T, 0>
{
static void add(reader_t_helper::accumulator_t& fmts)
{
reader_t_helper::format_accumulator_impl<T, 0>(fmts);
}
};
private:
template<typename T> struct map_dispatcher;
template<typename T, int N>
static void format_accumulator_impl(reader_t_helper::accumulator_t& fmts)
{
typedef typename boost::tuples::element<N, T>::type elem_t;
fmts.push_front(reader_t_helper::map_dispatcher<elem_t>::map());
}
};
template<> struct reader_t_helper::map_dispatcher<short>
{
static std::string const* map()
{
static std::string const fmt("%hi");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<unsigned short>
{
static std::string const* map()
{
static std::string const fmt("%hu");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<int>
{
static std::string const* map()
{
static std::string const fmt("%i");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<unsigned>
{
static std::string const* map()
{
static std::string const fmt("%u");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<long>
{
static std::string const* map()
{
static std::string const fmt("%li");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<unsigned long>
{
static std::string const* map()
{
static std::string const fmt("%lu");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<long long>
{
static std::string const* map()
{
static std::string const fmt("%lli");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<unsigned long long>
{
static std::string const* map()
{
static std::string const fmt("%llu");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<float>
{
static std::string const* map()
{
static std::string const fmt("%f");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<double>
{
static std::string const* map()
{
static std::string const fmt("%lf");
return &fmt;
}
};
template<> struct reader_t_helper::map_dispatcher<long double>
{
static std::string const* map()
{
static std::string const fmt("%Lf");
return &fmt;
}
};
template<std::size_t N> struct reader_t_helper::map_dispatcher<char[N]>
{
static std::string const* map()
{
static std::string const fmt(map_dispatcher::init());
return &fmt;
}
private:
static std::string init()
{
std::ostringstream oss;
oss << '%' << N << 'c';
return oss.str();
}
};
}
template<typename T>
struct reader_t
{
std::string format() const
{
typedef details::reader_t_helper::accumulator_t fmts_t;
typedef fmts_t::const_iterator citer_t;
static int const t_len = boost::tuples::length<T>::value;
fmts_t fmts;
details::reader_t_helper::format_accumulator<T, t_len - 1>::add(fmts);
std::string ret;
for (citer_t it = fmts.begin(), it_end = fmts.end(); it != it_end;)
{
ret += **it;
ret += ++it != it_end ? ',' : '\n';
}
return ret;
}
};
Add whatever reader_t_helper::map_dispatcher<>
specializations you need, as I'm sure I missed some.
Note that if you only need a type list, and not actual values of those types, the implementation could be simplified by using a boost::mpl::vector<T1, T2, ..., Tn>
rather than a boost::tuple<T1, T2, ..., Tn>
.
Also note that if need be, it would be possible to implement this as a 100% compile-time metafunction through use of boost::mpl::string<>
.
EDIT: Added support for char[N]
; I missed that requirement the first time around.
I'm not exactly an expert in this, but how about some C++ template metaprogramming.
Consider this for example:
template<class T> struct x {
static const char a = '\0';
static const char b = '\0';
};
template<> struct x<int> {
static const char a = 'd';
static const char b = '\0';
};
template<> struct x<double> {
static const char a = 'l';
static const char b = 'f';
};
You could use it to create a string like this:
string test;
test = "%" + x<int>::a + x<int>::b + ",";
test += "%" + x<int>::a + x<int>::b + ",";
test += "%" + x<double>::a + x<double>::b;
You might want to find some better names for a,b and x, and might need to figure out how to extract the types from a boost::tuple
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.