首页 > 编程语言 >现代C++(Modern C++)基本用法实践:四、模板

现代C++(Modern C++)基本用法实践:四、模板

时间:2023-07-13 13:02:06浏览次数:44  
标签:LOG int void Modern C++ func 模板 template

概述

C++的模板是泛型编程思想的一种实现。C++是强类型语言,处处强调类型。同样的加法运算,int和float的加法运算需定义两个函数(重载),而使用模板则可以只用一个函数(见下面示例)。
这类似我们面向对象所说的多态(定义加法运算,各个类型有不同的实现),所以是所谓静多态的一种实现方式,不同的是,模板在编译期展开生成int和float两个加法函数,如:

template<class T>
T add(T a, T b)
{
  return a + b;
}

int v1 = add<int>(1, 2);

// 不显式声明模板参数类型,编译器会试图推断
float v2 = add(1.5f, 2.5f);

/*
实际上编译器生成了两个函数
int add<int>(int a, int b)
float add<float>(float a, float b)
*/

模板不光支持函数模板,还有类模板,思想是一样的(详情见下面例子)。
模板还有一些特性机制如:模板特化,SFINAE(substitution failure is not an error 替换而非错误),变长参数模板等,另外模板在元编程中也是十分重要的组成部分,我对元编程没有太多实践,读者有兴趣可以自行搜索。

用法举例

参考测试项目ModernCppTest/modrenc_template.cpp
主要内容:

  • 函数模板&Lambda函数模板
  • 类模板
  • 别名模板
  • 变量模板
  • 值(枚举)作为模板参数(其实int类型也可以)
  • 模板特化
  • 变长参数模板
  • 模板函数的完美转发
#include "ModernCppTestHeader.h"

namespace n_template{

	template <class T>
	void template_func(T t)
	{
		LOG_VAR(t);
	}

	template <class T>
	class Number
	{
	public:
		T v;
		Number(T v) : v(v)
		{
			LOG_VAR(v);
		}
	};


	template <class T>
	constexpr T pi = T(3.1415926f);

	template <int INTVAL>
	void log_template_int_value()
	{
		LOG_VAR(INTVAL);
	}


	enum class EAnim : int {
		Other = 0,
		Cat = 1,
		Dog = 2,
	};

	template<EAnim Ty>
	class Anim
	{
	public:
		void Bark() { LOG("默认:动物叫"); }
	};

	template<>
	class Anim<EAnim::Dog>
	{
	public:
		void Bark() { LOG("狗:汪汪!"); }
	};

	template<>
	class Anim<EAnim::Cat>
	{
	public:
		void Bark() { LOG("猫:喵喵!"); }
	};


	// 注意递归基
	void log_values()
	{
		LOG("展开结束");
	}

	template<class T, class... ARGS>
	void log_values(T value, ARGS... args)
	{
		LOG(value);
		log_values(args...);
	}

	template<class T>
	void func_plus(T&& a)
	{
		auto v = a;
		LOG("func_plus v = " << a);
	}

	template<class T, class... ARGS>
	void func_plus(T&& a, T&& b, ARGS... args)
	{
		func_plus(a + b, std::forward<ARGS>(args)...);
	}

	template<class T>
	void func_mul(T&& a)
	{
		auto v = a;
		LOG("func_mul v = " << a);
	}

	template<class T, class... ARGS>
	void func_mul(T&& a, T&& b, ARGS... args)
	{
		func_mul(a + b, std::forward<ARGS>(args)...);
	}

	template <class... ARGS>
	void call_func(const std::string& name, ARGS&&... args)
	{
		if (name == "plus")
			func_plus(std::forward<ARGS>(args)...);
		else if (name == "mul")
			func_mul(std::forward<ARGS>(args)...);
		else
			LOG("Unknown function name: " << name);
	}
}


template<typename T>
using Num = n_template::Number<T>;

void template_test()
{
	LOG_FUNC();

	LOG_TAG(" 函数模板 ");
	{
		n_template::template_func(1);
		n_template::template_func(1.25f);

		LOG("Lambda 函数模板");
		auto f = []<class T> (T t) { LOG_VAR(t); };
		f(1);
		f(1.25f);
	}

	LOG_TAG("类模板");
	{
		n_template::Number(1);
		n_template::Number(1.25f);
	}

	LOG_TAG("别名模板");
	{
		Num<int>(1);
		Num<float>(1.25f);
	}

	LOG_TAG("变量模板");
	{
		auto v1 = n_template::pi<int>;
		auto v2 = n_template::pi<float>;
		LOG_VAR(v1);
		LOG_VAR(v2);

		n_template::log_template_int_value<10>();
		n_template::log_template_int_value<20>();
	}

	LOG_TAG("枚举变量模板&模板特化");
	{
		n_template::Anim<n_template::EAnim::Dog>().Bark();
		n_template::Anim<n_template::EAnim::Cat>().Bark();
		LOG("EAnim::Other 没有特化使用默认模板");
		n_template::Anim<n_template::EAnim::Other>().Bark();
	}

	LOG_TAG("变长参数模板");
	{
		n_template::log_values("jack", 10, 3.14f);
	}

	LOG_TAG("变长参数模板的完美转发");
	{
		n_template::call_func("plus", 1, 2, 3, 4);
		n_template::call_func("mul", 2, 3);
	}
}

标签:LOG,int,void,Modern,C++,func,模板,template
From: https://www.cnblogs.com/hggzhang/p/17523896.html

相关文章

  • 现代C++(Modern C++)基本用法实践:三、移动语义
    概述移动移动(move)语义C++引入了一种新的内存优化,以避免不必要的拷贝。在构造或者赋值的时候,如果实参是右值(或者左值由std::move转换成右值),便会匹配移动语义的函数调用如下述举例的Str(Str&&obj)。移动语义的本质是将资源(内存/句柄)转移给另一个对象,被转移资源的对象不应再被使......
  • 现代C++(Modern C++)基本用法实践:二、Lambda表达式
    概述lambda表达式,有时也被称为匿名函数。他提供了简短的,内联的函数对象。用法形式如:[capture](parameters)->return_type{body}具体用法如下文举例它的实现是由编译器决定的,在我的编译器上他是通过创建一个匿名类,通过重载()运算符,成为一个可调用对象,从而实现调用,类似://......
  • 现代C++(Modern C++)基本用法实践:七、范围遍历
    概述c++的for循环在语法上有些刻板,近几个版本对此进行了优化,支持了基于范围的for循环用法举例参考测试项目代码ModernCppTest/modrenc_range_for.cpp主要内容:数组遍历vector遍历字符串遍历map遍历#include"ModernCppTestHeader.h"#include<vector>#include<map>......
  • 现代C++(Modern C++)基本用法实践:六、constexpr编译时计算
    概述constexpr修饰的变量、函数、对象构造函数表示在编译时就可以确定。它经常用来计算一些编译期可以确定常数,和常数组成的表。比如编译时确定10000以内所有的素数,运行时用的时候直接查表。用法举例参考测试项目代码ModernCppTest/modrenc_constexpr.cpp主要内容:constexpr......
  • 现代C++(Modern C++)基本用法实践:零、概述&测试项目
    序言习惯上,我们把C++11之前的C++语法特性称之为“传统C++”,而把c++11之后的语法特性称之为现代C++。有一种说法称C++为中级语言,因为它的特性介于低级语言(如各类汇编语言)和高级语言(Python、C#)之间--一般来说,它在运行效率上比高级语言要高,而在开发效率上又比高级语言低一些。随着C......
  • 现代C++(Modern C++)基本用法实践:N、其他零散的常用特性
    概述这一篇简单介绍一些其他的比较实用的特性,如果读者想了解现代C++的全部特性,参考:cppreference其他特性预置和弃置函数default&delete在C++11中引入了default和delete关键字,允许程序员更加明确地控制类的默认操作(如默认构造函数,拷贝构造函数,拷贝赋值运算符,析构函数等)......
  • 现代C++(Modern C++)基本用法实践:八、线程支持
    概述在c++11之前,c++并未对线程编程提供直接的支持。在c++11之后,支持了线程管理、同步、条件变量等支持。在其他的c++库中(例如UE的线程库)还增加了多任务模型的抽象。用法举例参考测试项目的modrenc_auto_decltype.cpp文件主要内容:线程的创建使用future&async进行异步操作......
  • PAT-甲级-1007 Maximum Subsequence Sum C++
    Givenasequenceof K integers{ N1​, N2​,..., N​K }.Acontinuoussubsequenceisdefinedtobe{ Ni​, Ni+1​,..., Nj​ }where 1≤i≤j≤K.TheMaximumSubsequenceisthecontinuoussubsequencewhichhasthelargestsumofitselements.Fore......
  • c++ day 8
    今天终于来学习时间复杂度了当分析算法的时间复杂度时,我们通常关注以下几个方面来确定算法的执行时间:循环次数:循环是算法中常见的结构,它会重复执行一段代码。时间复杂度取决于循环的次数。例如,一个循环从1到n的遍历,时间复杂度就是O(n)。嵌套循环:如果算法中存在多个嵌套循环......
  • C# 使用Windows服务项目模板快速创建Windows服务程序
    之前写了一篇使用Topshelf创建Windows服务程序的文章:https://www.cnblogs.com/log9527blog/p/17325795.html还可以直接使用VS自带的Windows服务项目模板快速创建Windows服务程序 Service1.cs里面的OnStart和OnStop方法分别代表服务开始,服务停止时执行的逻辑 配置服务Serv......