使用基于boost :: tuple的fscanf构建regexp来读取文件

时间:2011-06-21 12:38:09

标签: c++ boost

我有几个数据文件,可以包含不同类型的数据。 例如,我可以有一个文件:int-int-double:

1,2,0.5
1,3,0.7    

或int-char [16] -double:

1,15c48e7d3a4857bb,0.1
2,49b49e45f46aa45b,0.3

我想构建一个可以被视为通用读者的对象。我想提供的是一个boost :: tuple类型,该对象必须能够为我提供一个适当的正则表达式来使用fscanf读取文件

该对象的基本代码是:

template <typename T>
class reader_t<typename T>
{
  ...
  std::string regexp() const;
}

之后,我将实例化一个给出适当的boost :: tuple格式的对象。

reader_t reader<boost::tuple<int, int, double> > reader;

要读取文件,我将使用方法'regexp'返回的正则表达式:

std::cout<<reader.regexp()<<std::endl;

在这种情况下,它应该给我:

"%d,%d,%lf\n"

我查看boost description,但我找不到我需要的东西。

有人有想法吗?

2 个答案:

答案 0 :(得分:1)

这应该让你开始:

#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;
    }
};

添加您需要的任何reader_t_helper::map_dispatcher<>专精,因为我确定我错过了一些。

请注意,如果您只需要类型列表,而不需要这些类型的实际,则可以使用boost::mpl::vector<T1, T2, ..., Tn>而不是boost::tuple<T1, T2, ..., Tn>来简化实施。

另请注意,如果需要,可以通过使用boost::mpl::string<>将其实现为100%编译时元函数。

编辑:添加了对char[N]的支持;我第一次错过了这个要求。

答案 1 :(得分:0)

我不是这方面的专家,但是一些C ++模板元编程怎么样。

以此为例:

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';
};

您可以使用它来创建这样的字符串:

string test;
test = "%" + x<int>::a + x<int>::b + ",";
test += "%" + x<int>::a + x<int>::b + ",";
test += "%" + x<double>::a + x<double>::b;

您可能希望为a,b和x找到一些更好的名称,并且可能需要弄清楚如何从boost::tuple中提取类型。