在我们的遗留代码中,我们尝试将原始值从char *转换为某种特定类型,如int,float,double,char(一堆char)等。
代码如下所示
char *data = db_data(process, retry_column);
int retry_time = *(int*)(data);
//......
data = db_data(process, user_name_column);
std::string user_name(data, std::strlen(data));
在不重新设计库的情况下获得变体数据类型的更好方法是什么?
如果唯一的方法是重新设计库,你会建议什么样的解决方案,而不是在性能和类型安全之间进行压缩(我希望同时获得两者),boost :: variant可以完成任务吗?
答案 0 :(得分:1)
如果您想要类型安全,您应该毫无疑问选择boost::variant
但是,这需要你重新编译db_data(),因为返回不再是char *。
因此,如果有太多事情需要完成,并且您希望从更轻松的变化开始,我可以为您提出以下模板和字符串案例的专业化:
template <typename T>
inline T vdata(char* val)
{ return *reinterpret_cast<T*>(val); }
template<>
inline string vdata(char* val)
{ return string(val); } // special case for strings
注意:此模板按值运行。因此它与你的解除引用的铸造指针略有不同,因为你不能将它用作左值来为它赋值(而*(int*)data = 12;
将是有效的)
使用此定义,您可以更改这样的遗留代码:
int retry_time = vdata<int>(data);
...
std::string user_name = vdata<string>(data);
当然,您可以通过避免使用临时数据来使其更简单:
模板 inline T vdb_data(int proc,char * col)//注意:使用与原始相同的参数签名,我不知道你使用的真实类型 {return vdata(db_data(proc,col)); }
但有些人指出,这个解决方案很不错,但不会给你带来类型安全。例如,在字符串版本中,至少进行一些一致性检查会很好(例如它终止,并且长度符合str :: max_size()。)
答案 1 :(得分:0)
显而易见的解决方案是boost::variant
。
即便如此,提供retry_column
类型int_column_t
以便使用int db_data(..., int_column_t)
重载可能很有用。
答案 2 :(得分:0)
有一个固有的问题,就是无法知道你得到的字节是否确实是正确的类型。它们只是0和1的流。因此无法确保数据库中的数据是正确的类型(除了数据大小考虑因素)。话虽这么说,你可以通过在数据类型上模板化db_data来避免客户端代码中的强制转换。然后,它可以验证大小是否正确,然后返回已转换为正确类型的数据。这将是这样的:
template<class DataType> DataType db_data();