简体   繁体   中英

Build a regexp to read a file using fscanf based on a boost::tuple

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM