C++设计新思维(泛型编程与设计模式之应用)之常整数映射为类别(2.4)

技术

模板偏特化,模板全特化

应用

1、有必要根据一个编译期常数调用一个或数个不同的函数
2、有必要在编译器实施"分派"(dispatch)

例子

如果打算在执行期进行分派(dispatch),可使用if-else或switch语句。大部分时候其执行期成本都微不足道。然后你还是无法常常那么做,因为if-else语句要求每一个分支都得编译成功。

假设你想设计一个泛型容器NiftyContainer,它将元素类型参数化:

template <class T>
class NiftyContainer
{
	...
	// 假设NiftyContainer内含指针,指向类型为T的对象。
};

为了复制NiftyContainer里的某个对象,你想调用其拷贝构造函数(针对非多态类)或虚函数clone()(针对多态类型)。
你以一个bool来作为调用哪种函数的条件

template <class Tbool 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;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值