[开源世界] 如何让 C++ 模板类支持同名多参数?
在C++中,根据函数参数个数的不同区分函数重载再常见不过了。也就是说,向下面这样的函数重载在C++中是合法的。
int max(int a, int b) { return a>b?a:b; }
int max(int a, int b, int c) { return max(a,b)>max(b,c)?max(a,b):max(b,c); }
当我们把这条经验扩展到C++的模板系统时,它仍然是有效的。
template<typename _T> void debug(_T a, std::string b) { cout<<a<<b; }
template<typename _T, typename _T1> void debug(_T a, _T1 b, std::string c) { cout<<a<<b<<c; }
但是当我们进一步将这条经验试图扩展到C++的类模板时,它失效了。也就是说,像下面这样的模板类在C++中是非法的(VC++编译器报告Debug模板参数太多)。
template<typename _T> struct Debug {
_T _a;
Debug(_T a) : _a(a) {}
void debug(std::string s) { cout<<_a<<s; }
};
template<typename _T, typename _T1> struct Debug {
_T _a;
_T1 _b;
Debug(_T a, _T1 b) : _a(a), _b(b) {}
void debug(std::string s) { cout<<_a<<_b<<s; }
};
为了能够让上面的定义在C++中变得合法,我们需要将各自的命名后面加上当前模板参数的个数(这是一般做法)。看起来就像下面这样。
template<typename _T> struct Debug0 {
void debug(_T a,std::string s) { cout<<a<<s; }
};
template<typename _T, typename _T1> struct Debug1 {
void debug(_T a,_T1 b,std::string s) { cout<<a<<b<<s; }
};
然而,我们真的找不到一种方法能够实现上述意图吗?答案可能是否定的。事实上在C++的模板规则中有这样的一条实现:你可以从一堆看起来一样的模板类中选择一个看起来符合的类然后继承它。也就是说,我们能够实现这样的一种形式:
template<typename _T> struct Debug : public one_struct_in_( Debug0, Debug1) {};
它的实现就需要本文将要介绍的模板参数系统。我认为这种技术的核心在于将函数指针的各部分的类型分开。也就是说,对一个模板类输入如下参数时,
Debug<void(int,int)>
能够获得如下的事实成立,
Debug<void(int,int)> : Debug1<int,int>
或者,对一个模板类输入如下参数时,
Debug<void(int)>
能够获得如下的事实成立,
Debug<void(int)> : Debug0<int>
客户端可以实现像下面这样的使用体验,
Debug<void(int)> a;
a.debug(3,"0");
Debug<void(int,string)> b;
b.debug(3, "4","0");
如果读者对这种技术感兴趣的话,请移步下面的网址下载示例程序。
https://tmplargs.codeplex.com/
顺便说一句,这个技术是完全开源的。