C++模板编程与泛型编程之函数模板(三)

C++模板编程与泛型编程之函数模板


缺省参数

  • 案例1
//普通函数
int mf(int tmp1, int tmp2)
{
	return 1;
}
int mf2(int tmp1, int tmp2)
{
	return 10;
}
//函数指针类型定义
typedef int(*FunType)(int, int); 
template <typename T,typename F = FunType>	
void testfunc(T i, T j, F funcpoint = mf)
{
	cout << funcpoint(i, j) << endl;
}
  • 对类型F设置默认类型为FunType ,对变量设置为函数指针为mf
  • 进行调用,没有指定第三个参数,则使用默认值mf。
testfunc(15, 16);
  • 指定第三个参数,则使用mf2。
testfunc(15, 16, mf2);

  • 案例2
template <typename T = int, typename U>
void testfunc2(U m)
{
	T tmpvalue = m;
	cout << tmpvalue << endl;
}

testfunc2(12);
  • 输入12,推断出U为int,T默认为int,编译通过。类模板不能这样指定缺省参数,凡是一个指定,后面类型参数都必须全部指定缺省参数。

非类型模板参数

  • 基本概念
    • 前面的函数模板涉及到的 模板参数都是 “类型 模板参数”需要用typename(class)来修饰(类型参数化
    • 模板参数还可以是 “非类型 模板参数(普通的参数)”,只是这个普通参数放到<>内

template < typename T, typename U ,int val = 100>
auto Add(T tv1,U tv2)
{
	return tv1 + tv2 + val;
}

cout << Add<float, float>(22.3f, 11.8f) << endl;
cout << Add<float, float,800>(22.3f, 11.8f) << endl;
  • 调用时没有指定第三个参数,则使用默认值100,也可以自己指定参数,如800。
  • c++17开始,支持非类型模板参数为auto类型。
template < typename T, typename U ,auto val = 100>
auto Add(T tv1,U tv2)
{
	return tv1 + tv2 + val;
}
  • 指定非类型模板参数的值时,一般给的都是常量。因为编译器在编译的时候就要能够确定非类型模板参数的值。
int k = 1000;	
cout << Add<float, float, k>(22.3f, 11.8f) << endl;
  • 编译器在编译的时候不知道 k 为1000,只有在运行的时候才能确定其值。编译器编译时必须确定知道 k 的值,所以上述代码编译会报错。

  • 并不是任何类型的参数都可以作为非类型模板参数
    • int类型可以,但double,float或者类类型string等等可能就不可以,不过double *这种指针类型可以。
  • 下面编译时会报 “ val 类型非法 ”的错误。
template < typename T, typename U ,double val = 12.3>
auto Add(T tv1,U tv2)
{
	return tv1 + tv2 + val;
}
  • double *这种指针类型可以,不报错
template <double *p>
void mft()
{
	cout << "mft()执行了" << endl;
}

double g_d = 1.3; 

mft<&g_d>();
  • 总结;
    • 一般允许做非类型模板参数的类型如下:(可能不断增加)
      • 整型或者枚举型;
      • 指针类型;
      • 左值 引用类型;
      • auto或者decltype(auto);
      • 可能还有其他类型,遇到自行总结。

比较奇怪的语法

  • 不管类型还是非类型模板参数,如果代码中没有用到,则参数名可以省略
//template <typename T,int value>
template <typename, int>
auto Add2()
{
	return 100;
}

cout << Add2<int,45>() << endl;
  • 如 T 和 value在后面代码中没有用到,可以省略不写,语法上不报错。

  • 类型前面可以增加一个typename修饰以明确标识一个类型
template <typename T, typename int value>
auto Add2()
{
	return 100;
}
  • 第一个typename修饰的是类型模板参数 T ,typename可以用class替换
  • 第二个typename仅仅表示修饰后面的类型,我们知道后面就是一个类型,为int,此处有画蛇添足之嫌。
    • 但是有些场合,当编译器不能区分出来后面是不是类型的时候(我们知道是一个类型),编译器会报错,此时就可以加上typename告诉编译器后面是一个类型。
  • 一般跟模板有关的类型名前面是需要typename

猜你喜欢

转载自blog.csdn.net/baidu_41388533/article/details/106887609
今日推荐