一直想写个CSV读写的模板,但是接口的定义一直是个问题。CSV每列都可以任意映射成C++基本类型,怎么把接口定义得既通用又灵活?最近发现C++11引入了tuple,接口也可以像python一样的方便漂亮,而且不再依赖boost库,真正做到Windows/Linux一套代码。
#ifndef _CSV_TO_TUPLES_H
#define _CSV_TO_TUPLES_H
#include <stdlib.h>
#include <string>
#include <istream>
#include <ostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <memory>
#include "common/common_utils.h"
namespace util {
namespace csv_tuple {
template <typename T>
class NullType
{
public:
explicit NullType()
: is_null(true) // by default, NULL value
{}
explicit NullType(const NullType& src)
: is_null(src.is_null), value(src.value)
{}
explicit NullType(const T& v)
: is_null(false), value(v)
{}
~NullType()
{}
void Reset()
{
// not all types can be reset by assigning of 0
*this = NullType();
}
NullType& operator=(const NullType& src)
{
this->is_null = src.is_null;
this->value = src.value;
return *this;
}
public:
bool is_null;
T value;
};
typedef NullType<char> NullChar;
typedef NullType<unsigned char> NullUChar;
typedef NullType<short> NullShort;
typedef NullType<unsigned short> NullUShort;
typedef NullType<int> NullInt;
typedef NullType<unsigned int> NullUInt;
typedef NullType<long long> NullBigInt;
typedef NullType<unsigned long long> NullUBigInt;
typedef NullType<float> NullFloat;
typedef NullType<float> NullReal;
typedef NullType<double> NullDouble;
typedef NullType<bool> NullBool;
typedef NullType<std::string> NullString;
template <typename T>
void StringToValue(const std::string& str, NullType<T>& value)
{
if (str.empty()) {
value.Reset();
}
else {
value.is_null = false;
StringToValue(str, value.value);
}
}
static inline void StringToValue(const std::string &str, char &value)
{
value = (char)atoi(str.c_str());
}
static inline void StringToValue(const std::string &str, unsigned char &value)
{
value = (unsigned char)atoi(str.c_str());
}
static inline void StringToValue(const std::string &str, short &value)
{
value = (short)atoi(str.c_str());
}
static inline void StringToValue(const std::string &str, unsigned short &value)
{
value = (unsigned short)atoi(str.c_str());
}
static inline void StringToValue(const std::string &str, int &value)
{
value = atoi(str.c_str());
}
static inline void StringToValue(const std::string &str, unsigned int &value)
{
value = (unsigned int)std::strtoul(str.c_str(), NULL, 10);
}
static inline void StringToValue(const std::string &str, long long &value)
{
#ifdef _WIN32
value = _atoi64(str.c_str());
#else
value = atoll(str.c_str());
#endif
}
static inline void StringToValue(const std::string &str, unsigned long long &value)
{
value = (unsigned long long)std::strtoull(str.c_str(), NULL, 10);
}
static inline void StringToValue(const std::string &str, bool &value)
{
value = atoi(str.c_str()) != 0;
}
static inline void StringToValue(const std::string& str, std::string& value)
{
value = str;
}
static inline void StringToValue(const std::string& str, float& value)
{
value = (float)atof(str.c_str());
}
static inline void StringToValue(const std::string& str, double& value)
{
value = atof(str.c_str());
}
// add more versions of StringToValue() if needed
#define TUPLE_SET_ITEM(tp, i) \
T##i t##i; \
StringToValue(subs[i], t##i); \
std::get<i>(tp) = t##i
template<typename T0>
void FillTuple(const std::vector<std::string>& subs,
std::tuple<T0>& tp)
{
TUPLE_SET_ITEM(tp, 0);
}
template<typename T0, typename T1>
void FillTuple(const std::vector<std::string>& subs,
std::tuple<T0, T1>& tp)
{
TUPLE_SET_ITEM(tp, 0);
TUPLE_SET_ITEM(tp, 1);
}
template<typename T0, typename T1, typename T2>
void FillTuple(const std::vector<std::string>& subs,
std::tuple<T0, T1, T2>& tp)
{
TUPLE_SET_ITEM(tp, 0);
TUPLE_SET_ITEM(tp, 1);
TUPLE_SET_ITEM(tp, 2);
}
template<typename T0, typename T1, typename T2, typename T3>
void FillTuple(const std::vector<std::string>& subs,
std::tuple<T0, T1, T2, T3>& tp)
{
TUPLE_SET_ITEM(tp, 0);
TUPLE_SET_ITEM(tp, 1);
TUPLE_SET_ITEM(tp, 2);
TUPLE_SET_ITEM(tp, 3);
}
template<typename T0, typename T1, typename T2, typename T3, typename T4>
void FillTuple(const std::vector<std::string>& subs,
std::tuple<T0, T1, T2, T3, T4>& tp)
{
TUPLE_SET_ITEM(tp, 0);
TUPLE_SET_ITEM(tp, 1);
TUPLE_SET_ITEM(tp, 2);
TUPLE_SET_ITEM(tp, 3);
TUPLE_SET_ITEM(tp, 4);
}
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
void FillTuple(const std::vector<std::string>& subs,
std::tuple<T0, T1, T2, T3, T4, T5>& tp)
{
TUPLE_SET_ITEM(tp, 0);
TUPLE_SET_ITEM(tp, 1);
TUPLE_SET_ITEM(tp, 2);
TUPLE_SET_ITEM(tp, 3);
TUPLE_SET_ITEM(tp, 4);
TUPLE_SET_ITEM(tp, 5);
}
template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6>
void FillTuple(const std::vec