- 论坛徽章:
- 44
|
本帖最后由 windoze 于 2015-10-27 17:25 编辑
回复 10# yulihua49
C++的模板参数不光可以是type,也可以是编译期常数,所有字面常量和constexpr常量都可以拿来做模板参数。
之前说variant的动态性在read的过程中体现的更明显,假如有一组针对基本类型的输入操作:
- Src &operator>>(Src&src, int &v) {...}
- Src &operator>>(Src&src, std::string &v) {...}
- Src &operator>>(Src&src, double &v) {...}
- ...
复制代码 那么就可以用和上面说到的write过程很类似的手段去read一个variant,具体代码可以参见variant_reader
把variant读进来之后就可用variant::get<type>将其转化为具体的类型,如果variant中的实际类型和要求的类型不符就会抛出bad_get异常。
比如说有一个DBField类型,大致的实现会是这样的:
- DBField &operator>>(DBField&src, int &v) {
- v=src.getInt();
- return src;
- }
- DBField &operator>>(DBField&src, std::string &v) {
- v=src.getString();
- return src;
- }
- ...
复制代码 然后你就可以写:
- template<size_t I, size_t N> struct DBRecord_reader {
- typedef typename cxl::to_variant<T>::type variant_type;
- template<typename T> void operator(DBRecord &rec, T &t){
- variant_type v;
- rec.getField(I) >> v;
- get<std::tuple_element<I, T>::type>()=v.get<std::tuple_element<I, T>::type>();
- DBRecord_reader<I+1, cxl::tuple_size<T>::value>()(rec, t);
- }
- };
- template<size_t N> struct DBRecord_reader<N, N> {
- template<typename T> void operator(DBRecord &rec, T &t){}
- };
- template<typename ...T>
- void Read_DBRecord(DBRecord &rec, T &t) {
- DBRecord_reader<0, cxl::tuple_size<T>::value>()(rec, t);
- }
复制代码 有了这一组针对基本类型的操作,你就可以动态处理任意的数据库记录,比如:
- typedef std::tuple<int, std::string ...> Your_Type;
- std::vector<Your_Type> vec;
- Connection conn=getConnection(...);
- ResultSet rs=conn.execute("SELECT ...");
- for(auto &&rec: rs) {
- Your_type x;
- Read_DBRecord(rec, x);
- vec.push_back(std::move(x));
- }
复制代码 上述代码可以把任意数据库的内容读进任意tuple里,不需要针对每种tuple定义什么东西。
但是这里有一个小问题,tuple可以用模板元编程技术遍历,但标准的struct/class不支持这种技术,所以我写的反射库的主要功能就是把一个struct/class映射成一个tuple,然后上述的代码就可以应用于这些struct,在这个过程中你不需要单独把struct和一个特定的数据库表映射起来,只需要把struct和一个tuple映射起来,就可以支持任意数据库表,同时还可以支持JSON/XML/CSV这些东西。 |
|