技术
模板偏特化,模板全特化
应用
1、有必要根据一个编译期常数调用一个或数个不同的函数
2、有必要在编译器实施"分派"(dispatch)
例子
如果打算在执行期进行分派(dispatch),可使用if-else或switch语句。大部分时候其执行期成本都微不足道。然后你还是无法常常那么做,因为if-else语句要求每一个分支都得编译成功。
假设你想设计一个泛型容器NiftyContainer,它将元素类型参数化:
template <class T>
class NiftyContainer
{
...
// 假设NiftyContainer内含指针,指向类型为T的对象。
};
为了复制NiftyContainer里的某个对象,你想调用其拷贝构造函数(针对非多态类)或虚函数clone()
(针对多态类型)。
你以一个bool来作为调用哪种函数的条件
template <class T, bool isPolymorphic>
class NiftyContainer
{
...
void doSomething()
{
T *pSomeObj = ...;
if (isPolymorphic) { // 多态
T *pNewObj = pSomeObj->clone();
} else { // 非多态
T *pNewObj = new T(*pSomeObj);
// T *pNewObj = new T();
// *pNewObj = *pSomeObj;
}
}
};
问题是,编译器并不一定都会编译成功,如果使用多态算法,那么对于任何一个未定义clone函数的类或者clone是private的类
,都将使doSomething
函数无法编译成功。而对于非多态类型,如果禁用了拷贝构造或者拷贝构造在private区域也同样将无法编译成功。所以想要编译成功,则T类型必须同时具有clone()
和拷贝构造函数
才能编译成功。
如果我只需要clone
或拷贝构造函数
中的一种呢?
虽然有很多种解法,但是以下这种解法最简单易理解。
template <int v>
struct Int2Type
{
enum { value = v };
};
template <class T, bool isPolymorphic>
class NiftyContainer
{
public:
void doSomething(T *pObj)
{
doSomething(pObj, Int2Type<isPolymorphic>());
}
private:
void doSomething(T *pObj, Int2Type<true>)
{
T *pNewObj = pObj->clone();
}
void doSomething(T *pObj, Int2Type<false>)
{
T *pNewObj = new T(*pObj);
}
};
这种手法在STL代码中很常见,只是形式略有不同而已。
这种小技巧之所以有效,最主要原因是编译器不会编译一个未被使用到的template函数,只会对它做语法检测。至于此技巧之所以有用,是因为在template代码中大部分情形要在编译期做流程分派动作。
测试
/*************************************************************************
> File Name: main.cc
> Author:
> Brief:
> Created Time: Mon 23 Jan 2023 03:46:27 PM CST
************************************************************************/
#include <iostream>
using namespace std;
template <int v>
struct Int2Type
{
enum
{
value = v
};
};
template <class T, bool isPolymorphic>
class NiftyContainer
{
public:
void doSomething(T *pObj)
{
doSomething(pObj, Int2Type<isPolymorphic>());
}
private:
void doSomething(T *pObj, Int2Type<true>)
{
T *pNewObj = pObj->clone();
}
void doSomething(T *pObj, Int2Type<false>)
{
T *pNewObj = new T(*pObj);
delete pNewObj;
}
};
class Test
{
public:
Test() { printf("%s()\n", __func__); }
Test(const Test &o) { printf("%s(const Test &o)\n", __func__); }
~Test() { printf("%s()\n", __func__); }
};
int main(int argc, char **argv)
{
Test t;
NiftyContainer<Test, false> container;
container.doSomething(&t);
return 0;
}