策略技术中的算法策略

  • 在之前博客中funcsum()函数模板中,实现了对数组元素的求和运算。求和在这里可以看作一种算法,扩展一下思路,对数组元素求差、求乘积、求最大值和最小值等,都可以看作算法。
  • 而当前的funcsum()函数模板中,已经将数组元素的求和算法固定写在了程序代码中,为了灵活地将求和算法调整为求乘积、求最大值等算法,可以通过引入一个策略(policy)类SumPolicy达到目的。
// 求和策略类以实现求和算法
struct SumPolicy
{
	// 静态成员函数模板
	template<typename sumT,typename T> // sumT是和值类型,T是数组元素类型
	static void algorithm(sumT& sum, const T& value) // 该策略类的核心算法
	{
		sum += value;
	}
};

接着,为funcsum()函数模板增加一个新的类型模板参数,这个模板参数的默认值就是这个策略类。
修改funcsum()函数模板

template<typename T,typename U = SumFixedTraits<T>,typename V = SumPolicy>
auto funcsum(const T* begin, const T* end)
{
	typename U::sumT sum = U::initValue();

	for (;;)
	{
		// sum += (*begin); 此行被下面一行取代
		V::algorithm(sum, *begin);
		if (begin == end)
			break;
		++begin;
	}
	return sum;
}

如果要计算一个整型数组中元素的最小值,如何实现?第1件想到的事情就是写一个新的策略类,如这里写一个MinPolicy类(仿照SumPolicy类的写法)。

struct MinPolicy
{
	template<typename minT,typename T>
	static void algorithm(minT& min, const T& value)
	{
		if (min > value)
			min = value;
	}
};

main()主函数中重新写入代码:

#include "killCmake.h"

#include<string>

using namespace std;

template<typename T>
struct SumFixedTraits;

template<>
struct SumFixedTraits<char>
{
	using sumT = int;
	static sumT initValue() {
		return 0;
	}
};

// 最求值策略技术时,为了求最小值,初始化需要很大
// 所以初始值可以为int最大值21亿
template<>
struct SumFixedTraits<int>
{
	using sumT = __int64;
	static sumT initValue() {
		return 2100000000;
	}
};

template<>
struct SumFixedTraits<double>
{
	using sumT = double;
	static sumT initValue() {
		return 0.0;
	}
};

template<typename T,typename U = SumFixedTraits<T>>
auto funcsum(const T* begin, const T* end)
{
	// using sumT = typename SumFixedTraits<T>::sumT;  本行不需要
	// sumT sum = SumFixedTraits<T>::initValue();  本行不需要
	typename U::sumT sum = U::initValue();

	for (;;)
	{
		sum += (*begin);
		if (begin == end)
			break;
		++begin;
	}
	return sum;
}

// 求和策略类以实现求和算法
struct SumPolicy
{
	// 静态成员函数模板
	template<typename sumT,typename T> // sumT是和值类型,T是数组元素类型
	static void algorithm(sumT& sum, const T& value) // 该策略类的核心算法
	{
		sum += value;
	}
};

template<typename T,typename U = SumFixedTraits<T>,typename V = SumPolicy>
auto funcsum(const T* begin, const T* end)
{
	typename U::sumT sum = U::initValue();

	for (;;)
	{
		// sum += (*begin); 此行被下面一行取代
		V::algorithm(sum, *begin);
		if (begin == end)
			break;
		++begin;
	}
	return sum;
}

struct MinPolicy
{
	template<typename minT,typename T>
	static void algorithm(minT& min, const T& value)
	{
		if (min > value)
			min = value;
	}
};




int main()
{
	//char my_char_array[] = "abc";
	//std::cout << (int)(funcsum(&my_char_array[0], &my_char_array[2])) << std::endl;

	//std::cout << (int)(funcsum<char, SumFixedTraits<int>>(&my_char_array[0], &my_char_array[2])) << std::endl;

	int my_int_array1[] = { 10,15,20 };
	std::cout << funcsum<int, SumFixedTraits<int>, MinPolicy>(&my_int_array1[0], &my_int_array1[2]) << std::endl;

	return 0;
}

C++新经典模板与泛型编程:策略技术中的算法策略-LMLPHP
这个程序真的很经典,个人觉得,应该属于中上乘武功

  • 运行程序,看一看新增的代码结果是否正确,最开始发现结果为0,显然这个结果是不正确的。究其原因,在funcsum()中,sum(用于保存数组元素最小值的变量)的初值被设置为0。如果是计算数组元素和值,则sum的初值被设置为0是很正常的;但如果要计算数组元素的最小值,则把sum的初值设置为0是不正常的(因为数组中元素的最小值也很可能比0大,有这个0存在,就无法找到数组中元素的真正最小值)。
  • 解决方案有以下两个。
  • (1)可以给funcsum()函数模板增加一个非类型模板参数,用于把初值传递进来。
  • (2)也可以重新写一个固定萃取类模板取代当前的SumFixedTraits模板。这里采用后一种解决方案,书写一个新的固定萃取类模板,取名为MinFixedTraits
#include "killCmake.h"

#include<string>

using namespace std;

template<typename T>
struct SumFixedTraits;

template<>
struct SumFixedTraits<char>
{
	using sumT = int;
	static sumT initValue() {
		return 0;
	}
};

// 最求值策略技术时,为了求最小值,初始化需要很大
// 所以初始值可以为int最大值21亿
template<>
struct SumFixedTraits<int>
{
	using sumT = __int64;
	static sumT initValue() {
		return 2100000000;
	}
};

template<>
struct SumFixedTraits<double>
{
	using sumT = double;
	static sumT initValue() {
		return 0.0;
	}
};

template<typename T>
struct MinFixedTraits;

template<>
struct MinFixedTraits<int>
{
	// 求最小值,结果类型与元素类型相同即可
	// 为名字统一,都用sumT这个名字
	using sumT = int;

	static sumT initValue()
	{
		// 这里给整型最大值,相信任何一个数组元素都不会比这个值更大
		// 因此可以顺利找到数组元素中的最小值
		return INT_MAX;
	}
};

// 求和策略类以实现求和算法
struct SumPolicy
{
	// 静态成员函数模板
	template<typename sumT,typename T> // sumT是和值类型,T是数组元素类型
	static void algorithm(sumT& sum, const T& value) // 该策略类的核心算法
	{
		sum += value;
	}
};

template<typename T,typename U = SumFixedTraits<T>,typename V = SumPolicy>
auto funcsum(const T* begin, const T* end)
{
	typename U::sumT sum = U::initValue();

	for (;;)
	{
		// sum += (*begin); 此行被下面一行取代
		V::algorithm(sum, *begin);
		if (begin == end)
			break;
		++begin;
	}
	return sum;
}

struct MinPolicy
{
	template<typename minT,typename T>
	static void algorithm(minT& min, const T& value)
	{
		if (min > value)
			min = value;
	}
};

int main()
{
	int my_int_array1[] = { 10,15,20 };
	std::cout << funcsum<int, MinFixedTraits<int>, MinPolicy>(& my_int_array1[0], & my_int_array1[2]) << std::endl;

	return 0;
}

C++新经典模板与泛型编程:策略技术中的算法策略-LMLPHP
运行程序,新增的代码行结果为10,一切正常。

12-08 12:44