我正在尝试将数据类型从文件映射到内存,因此我有一个类来获取每列的信息。 不同的类型具有不同的映射参数,因此我为每个支持的类型创建了具有适当参数的结构。我设法通过这种方式解决了类型安全的问题,现在我正在使用一个模板,即数字类型,它们共享相同的属性,只有类型不同。 唯一的问题仍然是相当难看,就是我不能仅根据支持的类型分配正确的枚举。
如下例所示,如果是数字类型,我手动必须在示例代码中分配关联类型(c5
和c6
)。现在我想知道是否有更优雅的解决方案,以便我可以使用一些模板技术(enable_if
?)根据支持的类型选择正确的枚举值(c7
是预期的目标示例)。
我正在使用支持C + 11子集的Visual Studio 2010。
#define _CRT_SECURE_NO_WARNINGS
#include <time.h>
#include <type_traits>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
typedef char byte_t;
typedef unsigned char ubyte_t;
typedef short word_t;
typedef unsigned short uword_t;
typedef unsigned short date_t;
typedef char string_t;
class ColumnDef
{
public:
typedef enum
{
T_UNDEFINED,
T_byte,
T_ubyte,
T_word,
T_uword,
T_size_t,
T_string,
T_std_string,
T_date_string,
T_date,
T_MAX
} ColumnDefType;
typedef enum
{
DF_UNDEFINED,
DF_TTMMYY,
DF_YYMMTT,
DF_TTMMYYYY,
DF_YYYYMMTT,
DF_TT_MM_YYYY,
DF_YYYY_MM_TT,
DF_MAX
} DateFormat;
class cstring_type
{
public:
ColumnDefType Type;
const char *Adress;
size_t MaxLen;
static cstring_type init(const char *p, size_t nMaxLen) { cstring_type t = {T_string, p, nMaxLen}; return t; };
};
class cpp_string_type
{
public:
ColumnDefType Type;
std::string *Adress;
static cpp_string_type init(std::string *p) { cpp_string_type t = {T_std_string, p}; return t; };
};
class ubyte_type
{
public:
ColumnDefType Type;
ubyte_t *Adress;
ubyte_t Default;
static ubyte_type init(ubyte_t *p, ubyte_t nDef) { ubyte_type t = {T_ubyte, p, nDef}; return t; };
};
class date_type
{
public:
ColumnDefType Type;
date_t *Adress;
date_t Default;
DateFormat Format;
static date_type init(date_t *p, date_t nDef, DateFormat fmt) { date_type t = {T_date, p, nDef, fmt}; return t; };
};
template <typename T, ColumnDefType E>
class numeric
{
public:
ColumnDefType Type;
T *Adress;
T Default;
static numeric<T, E> init(T *p, T nDef) { numeric<T, E> t = {E, p, nDef}; return t; };
};
public:
ColumnDef(void) { mType = T_UNDEFINED; }
ColumnDef(ubyte_type const &t) { mType = t.Type; ub = t; }
ColumnDef(date_type const &t) { mType = t.Type; d = t; }
ColumnDef(cpp_string_type const &t) { mType = t.Type; cps = t; }
ColumnDef(cstring_type const &t) { mType = t.Type; cs = t; }
ColumnDef(numeric<size_t, T_size_t> const &t) { mType = t.Type; st = t; }
ColumnDef(numeric<byte_t, T_byte> const &t) { mType = t.Type; b = t; }
virtual ~ColumnDef(void)
{
}
void func(ColumnDefType nType)
{
switch(nType)
{
case T_byte:
{
byte_t *p = b.Adress;
if(!p)
break;
}
break;
case T_size_t:
{
size_t *p = st.Adress;
if(!p)
break;
}
break;
case T_ubyte:
{
ubyte_t *p = ub.Adress;
if(!p)
break;
}
break;
default:
std::cout << "Unknown" << std::endl;
break;
}
}
private:
ColumnDefType mType;
union
{
ubyte_type ub;
date_type d;
cpp_string_type cps;
cstring_type cs;
numeric<size_t, T_size_t> st;
numeric<byte_t, T_byte> b;
};
};
int main()
{
std::string s = "value";
date_t dt;
char tst[5];
size_t n;
byte_t b;
// Correct examples
ColumnDef c0(ColumnDef::date_type::init(&dt, 0, ColumnDef::DF_YYYY_MM_TT));
ColumnDef c1(ColumnDef::cstring_type::init(tst, sizeof(tst)));
ColumnDef c2(ColumnDef::cpp_string_type::init(&s));
ColumnDef c3(ColumnDef::numeric<byte_t, ColumnDef::T_byte>::init(&b, 0));
ColumnDef c4(ColumnDef::numeric<size_t, ColumnDef::T_size_t>::init(&n, 0));
// Wrong intialization causes a compiler error because type doesn't match enum. Only T_size_t should be allowed here.
ColumnDef c5(ColumnDef::numeric<size_t, ColumnDef::T_std_string>::init(&n, 0));
ColumnDef c6(ColumnDef::numeric<size_t, ColumnDef::T_byte>::init(&n, 0));
ColumnDef c7(ColumnDef::numeric<size_t>::init(&n, 0)); // should assign the correct type automatically inferred by the supported type
return 0;
}
答案 0 :(得分:0)
您可以在类型和枚举值之间编写映射,然后在代码中重复使用它:
namespace details {
template <typename T> struct TypeToEnum;
template <>
struct TypeToEnum<size_t> {
static const ColumnDef::ColumnDefType value = ColumnDef::T_size_t;
};
template <>
struct TypeToEnum<char> {
static const ColumnDef::ColumnDefType value = ColumnDef::T_byte;
};
}
template <typename T>
ColumnDef::numeric<T> ColumnDef::numeric<T>::init(T *p, T nDef)
{
ColumnDef::numeric<T> t = {details::TypeToEnum<T>::value, p, nDef};
return t;
}