template语法总结(2)

最近闲来无事,在github上找打了facebook开发的基础库源码,在代码阅读的过程中,看到了很多新颖的template的语法。边看变查,同时记录一下,以免遗忘。

1.  std::enable_if定义

通过跳转其定义的头文件,可以看到标准库中对该模板函数的定义如下。若_Test变量的取值为false则type未定义,否则type定义为_Ty。

	// TEMPLATE CLASS enable_if
template<bool _Test,
	class _Ty = void>
	struct enable_if
	{	// type is undefined for assumed !_Test
	};

template<class _Ty>
	struct enable_if<true, _Ty>
	{	// type is _Ty for _Test
	typedef _Ty type;
	};

所以针对如下测试测试代码结果为:

int main()
{
	// EnableCheck的类型为void,代码可以编过
	using EnableCheck = std::enable_if<std::true_type::value>::type;
	// EnableCheck的类型未定义,代码可以编不过
	// using EnableCheck = std::enable_if<std::false_type::value>::type;

	return 0;
}

2.  template中匿名参数的使用

在template参数定义时,有时使用匿名参数来完成对部分参数条件的校验,只有校验通过才能够正常编译过,否则编译不过,如:

#include <iostream>

template<typename T>
struct NoneInt
{
	static const bool value = true;
};

template<>
struct NoneInt<int>
{
	static const bool value = false;
};

template <typename RetType, typename = std::enable_if<NoneInt<RetType>::value>::type>
RetType Func()
{
	std::cout << "hello" << std::endl;
	return 0;
}

int main()
{
	//可编译过
	Func<float>();
	//可编译不过
	//Func<int>();

	return 0;
}

其中第二个 匿名模板参数就是对返回值的校验,只有返回值为int才能够编译通过。

 

3.  对模板定义特换方式的学习:

模板特化不只是对模板参数列表中的部分(或全部)参数类型指定,以下的方式同样是特化:

template <typename T>
Fuction;

template <typename RetType, typename... Args>
Fuction<RetType(Args...)>
{

}

4.  偏特化仅适用于模板类,不适用于模板函数。而且偏特化中明确指定类型,在构造函数的类型实参中仍需要指定,除非在全模板中有指定默认参数。如下

template <typename E, typename Enabled = void>
struct IsEnumUnderlying : std::false_type
{
};

template <typename E>
struct IsEnumUnderlying<E, typename std::enable_if<std::is_enum<E>::value>::type>
: std::integral_constant<bool, std::is_signed<typename std::underlying_type<E>::type>::value>
{
};

void TestDefaultParam()
{
    enum EnumType {};
    struct NonEnum {};

    // 调用偏特化版本
    IsEnumUnderlying<EnumType> a1;
    // 调用全定义版本
    IsEnumUnderlying<NonEnum> a2;     
}

查看std::enable_if的定义可知,其仅对模板常数取值为true有Type定义,在模板推导时若模板常数取值为false将导致匹配失败。这种方式可用于对前置模板实参的条件限定,即只有同时匹配类型且满足限定条件时才能够完全匹配该模板定义。另外,类模板的构造函数不进行模板形参的类型推导。

5. 模板变参列表的使用

如下函数定义,第一个参数为函数指针,第二个参数为变参列表。在FunctionInvoke中调用该函数,通过forward将参数转发给对应的函数。标准库中的make_shared和thread的构造函数,都是采用与FunctionInvoke类型的定义方式。

template <typename F, typename... Args>
void FunctionInvoke(F f, Args... args)
{
	f(std::forward<Args>(args)...);
}

void printHello(int a)
{
	cout << "Hello" << endl;
}

void TestInvoker()
{
	FunctionInvoke(&printHello, 10);
}

6. 常量定义

template <typename T>
struct IsInt
{
	constexpr static bool value = false;
};

template <>
struct IsInt<int>
{
	constexpr static bool value = true;
};

// 简化模板的使用
template <typename U>
constexpr bool IsInt_v = IsInt<U>::value;

void Test()
{
    //调用方式如下,输出为false
    cout << IsInt_v<float> << endl;
}

7. 移动语义和完美转发

std::move生成的是右值,std::forward是将原来的类型,转发给下一个参数使用(赋值或接口调用)。

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值