tuple的应用

tuple的本质是一个容纳各种数据类型成员的“结构体”。很早之前,我发现它和数据库的记录很像,都是字段的集合。用tuple可以做数据库编程的利器。

下面是一个基本框架,可抓取host应用程序的变量,可区分左值和右值。对于host应用程序的左值,希望它能同数据库api的绑定变量关联。很多数据库都支持绑定变量的思想。

对于右值,认为它在sql语句中起到直接量的作用,而右值往往来源于host应用程序的文字直接量

#include <iostream>
#include <sstream>
#include <type_traits>

namespace ext{

	// tuple
	template<class... _Types> class tuple;

	template<> class tuple<> {};

	template<class _This, class... _Rest>
	class tuple<_This, _Rest...> : private tuple<_Rest...>
	{
	public:
		_This _Myfirst;

		typedef tuple<_Rest...> _Mybase;

		template<class Head, class... Rest>
		explicit tuple(Head&& arg0, Rest&&... args)
			: _Mybase(std::forward<Rest>(args)...),
			_Myfirst(std::forward<Head>(arg0))
		{	
		}
	};

	// tuple_element
	template<size_t _Index, class _Tuple> struct tuple_element;

	// select first element
	template<class _This, class... _Rest>
	struct tuple_element<0, tuple<_This, _Rest...>>
	{
		typedef _This& type;
		typedef tuple<_This, _Rest...> _Ttype;
		typedef _This original_type;
	};

	// recursive tuple_element definition
	template <size_t _Index, class _This, class... _Rest>
	struct tuple_element<_Index, tuple<_This, _Rest...>>
		: public tuple_element<_Index - 1, tuple<_Rest...> >
	{
	};

	// get reference to _Index element of tuple
	template<size_t _Index, class... _Types> inline
		typename tuple_element<_Index, tuple<_Types...>>::type
		get(tuple<_Types...>& _Tuple)
	{
		typedef typename tuple_element<_Index, tuple<_Types...>>::_Ttype _Ttype;
		return (((_Ttype&)_Tuple)._Myfirst);
	}

	//if the  element at _Index is rvalue,then return true
	template<size_t _Index, class... _Types> inline
		bool is_rvalue(tuple<_Types...>& _Tuple)
	{
			typedef typename tuple_element<_Index, tuple<_Types...>>::original_type original_type;
			return std::is_rvalue_reference<original_type>::value;
    }

	template<class... Types>
	tuple<Types&&...> forward_as_tuple(Types&&... args)
	{
		return ext::tuple<Types&&...>(std::forward<Types>(args)...);
	}

	//封装了values子句,所需要的一些变量或文字常量
	template<class... Types>
	class values_wrapper{
	public:
		values_wrapper(Types&&... args) : tp_(std::forward<Types>(args)...){};
		ext::tuple<Types&&...> tp_;
	};

	//利用函数的参数推导能力,简化客户程序员编写代码
	template<class... Types>
	values_wrapper<Types&&...> values(Types&&... args){
		return values_wrapper<Types&&...>(std::forward<Types>(args)...);
	}


	//judge if one type is tuple
	template<class T>
	struct is_tuple{
		static const bool value = false;
	};

	template<class... Types>
	struct is_tuple<ext::tuple<Types...> >{
		static const bool value = true;
	};
};

class C_SQL{
public:
	template<typename... Args>
	friend C_SQL& operator%(C_SQL& sql , ext::values_wrapper<Args...> &tp);
	friend C_SQL& operator%(C_SQL& sql,  const char* stat);

	std::stringstream txt_;
	std::string sep_; //逗号分隔符

	void print(){
		std::cout << txt_.str() << std::endl;
	}
};

template<class Tuple, std::size_t N>
struct process_values {
	static void do_process(Tuple& t, C_SQL& sql)
	{
		process_values<Tuple, N - 1>::do_process(t,sql);

		sql.txt_ << sql.sep_;
		sql.sep_ = ",";

		if (ext::is_rvalue<N>(t)){
			sql.txt_ << ext::get<N>(t);
		}
		else{
			sql.txt_ << "?";
		}
		return;
	}
};

template<class Tuple>
struct process_values<Tuple, 0>{
	static void do_process(Tuple& t, C_SQL& sql)
	{
		sql.txt_ << sql.sep_;
		sql.sep_ = ",";
		
		if (ext::is_rvalue<0>(t)){
			sql.txt_ << ext::get<0>(t);
		}
		else{
			sql.txt_ << "?";
		}
		return;
	}
};

template<typename... Args>
C_SQL& operator%(C_SQL& sql, ext::values_wrapper<Args...>& va){
    
	sql.txt_ << "values ( ";
	sql.sep_ = "";
	process_values<decltype(va.tp_), sizeof...(Args)-1 >::do_process(va.tp_, sql);
	sql.txt_ << ")";
	return sql;
}

C_SQL& operator%(C_SQL& sql, const char* stat){
	sql.txt_ << stat;
	return sql;
}

int main()
{
	
	using namespace ext;

	C_SQL sql;
	int a = 0;	
	sql % "insert into t_test(col1,col2,col3) " % values(a,2,3);

	sql.print();

	return 0;
}
c++11的出现,values支持任意长度的参数列表,而在c++11之前,boost的tuple支持的参数列表个数是受限的。
通过打印print语句,发现左值a被正确识别,也被替换为?。右值2,3被sql语句保留为文字量。测试基本通过。

基本的模板技术都是从网友博客拷贝出来修改的,技术细节和原理不是非常透彻的理解(但也不是一窍不通,否则也改不出来)。

改进方向:1)host变量要真正的绑定到数据库api中去

                    2)这个例子只支持了values子句,还需要支持like子句,between子句,in子句等。in 子句可以用数组实现,like子句可以用std::pair实现。

此框架可以无缝的整合host应用程序的本地变量,完全隐藏数据库api的实现细节。也可以彻底的同传统的sql拼接字符串的原始低效方法说再见。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值