C++STL - 函数模板

模板主要是为了泛型编程,做到与类型无关

模板有函数模板和类模板,本文主要整理的是函数模板

1.函数模板定义

template<typename 类型形参1,typename 类型形参2,...>

返回类型 函数模板名(调用形参表){函数体}

在返回类型,调用形参表和函数体中,所需要类型的地方都可以引用模板形参表中类型形参

template<typename A,typenamen B,typename _C>
A function(B arg){
    _C var;
    ...
}

2.使用

函数模板名<类型形参1,类型形参2,...>(调用实参表)

即用<>中的替换template<>中的内容

eg:

int i = function<int,double,string>(1.23);

char c = function<char,string,Studnet>("hello");

3.类型参数

类型形参:前面必须带有typename或class关键字.

类型实参:传递给函数模板的类型实参既可以是基本类型(char/int/double等),也可以是类类型(Student/Teacher),甚至可以是其他模板实例化的类型(string),同时传递给函数模板的类型实参必须满足模板实现的具体要求, 否则将引发编译错误.

#include <iostream>
using namespace std;

template<typename T>
T add (T x, T y) {
    return x + y;
}

class Integer {
public:
    Integer (int arg = 0) : m_var (arg) {}
    friend ostream& operator<< (ostream& os,Integer const& i) {
        return os << i.m_var;
    }
    Integer const operator+ (Integer const& rhs) const {
        return m_var + rhs.m_var;
    }
private:
    int m_var;
};
int main (void) {
    cout << add<int> (123, 456) << endl;
    cout << add<double> (1.3, 4.6) << endl;
    cout << add<string> ("Hello, ", "World !") << endl;
//  cout << add<char const*> ("Hello, ","World !") << endl;
    cout << add<Integer> (123, 456) << endl;
    return 0;
}

4.延迟编译

每个函数模板事实上都要被编译两次:

(1)第一次是在编译器看到该函数模板被定义的时候,这时的编译器只对该函数模板做一般性的语法检查(与类型无关),然后生成关于该函数模板的内部表示

(2)第二次是在编译器看到该函数模板被调用的时候,在用所提供的类型实参,结合之前生成的内部表示中的类型形参,做与类型相关的语法检查,并生成该函数模板的二进制指令代码.

5.隐式推断

(1)如果函数模板调用参数(园括号里的参数)的类型 相关与该模板的参数<尖括号里的参数>,那么在调用该函数模板的时候,即使不显示指定模板参数,编译器也有能力根据调用参数的类型隐式推断出正确的模板参数类型,这就叫模板参数的隐式推断.

(2)但是注意:如果编译器隐式推断的类型,和程序设计者所期望的类型不一致,有可能导致编译错误.

#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T> void foo (T x, T y) {
    cout << "foo: " << typeid (x).name () << ‘ ‘ << typeid (y).name () << endl;
}
template<typename T> void bar (T const& x, T const& y) {
    cout << "bar: " << typeid (x).name () << ‘ ‘ << typeid (y).name () << endl;
}
template<typename R, typename T> R hum (T x) {
    R y;
    cout << "hum: " << typeid (x).name () << ‘ ‘ << typeid (y).name () << endl;
    return y;
}
void f1 (int x, int y) {}
void f2 (double x, double y) {}
int main (void) {
    int a, b;
    foo (a, b); // i i
    double c, d;
    bar (c, d); // d d
    char e[256], f[256];
    foo (e, f); // Pc Pc
    bar (e, f); // A256_c A256_c

//  cout << sizeof (e) << endl; // 256
//  char (*p)[256] = &e;
//  e[0] = ‘C‘; // *(e+0) = ‘C‘

    foo ("hello", "tarena"); // PKc PKc
//  bar ("hello", "tarena"); // A6_c A7_c
    bar<string> ("hello", "tarena"); // Ss Ss
    bar (string ("hello"), string ("tarena"));
    f1 (a, c); // c: double -> int
    f2 (a, c); // a: int -> double

//  int i = 1.2;
//  cout << i << endl;

//  隐式推断的同时不能隐式转换
//  foo (a, c); // c: double -> int, T=int
                // a: int -> double, T=double
    foo ((double)a, c); // d d
    foo (a, (int)c);    // i i
    foo<double> (a, c); // d d
    foo<int> (a, c);    // i i
//  a = hum (c);        // 返回值的类型不参与隐式推断
    a = hum<int> (c);   // d i
    return 0;
}

6.重载

与普通函数一样,函数模板也可以形成重载关系,类型的约束性越强的版本越被有限选择

#include <iostream>
#include <typeinfo>
#include <cstring>
using namespace std;
// 两个任意类型值的最大值
template<typename T>
T const& max (T const& x, T const& y) {
    cout << "<1" << typeid (x).name () << ‘>‘ << flush;
    return x < y ? y : x;
}
// 两个任意类型指针所指向目标的最大值
template<typename T>
T* const& max (T* const& x, T* const& y) {
    cout << "<2" << typeid (x).name () << ‘>‘ << flush;
    return *x < *y ? y : x;
}
// 两个字符指针所指向字符串的最大值
char const* const& max (char const* const& x,char const* const& y) {
    cout << "<3" << typeid (x).name () << ‘>‘ << flush;
    return strcmp (x, y) < 0 ? y : x;
}
/*
char const* max (char const* x,char const* y){
    cout << "<3" << typeid (x).name () << ‘>‘ << flush;
    return strcmp (x, y) < 0 ? y : x;
}
*/
// 三个任意类型值的最大值
template<typename T>
T const& max (T const& x, T const& y,
    T const& z) {
    cout << "<4" << typeid (x).name () << ‘>‘ << flush;
    return ::max (::max (x, y), z);
}
/*
// 两个字符指针所指向字符串的最大值
char const* const& max (char const* const& x,char const* const& y) {
    cout << "<3" << typeid (x).name () << ‘>‘ << flush;
    return strcmp (x, y) < 0 ? y : x;
}
*/
int main (void) {
    int a = 123, b = 456;
    cout << ::max (a, b) << endl;
    cout << *::max (&a, &b) << endl;
    char const* c = "ab", *d = "abc";
    cout << ::max (c, d) << endl;
    cout << ::max<> (c, d) << endl;
    cout << ::max<char const*> (c, d) << endl;
    char const* e = "abcd";
    char const* const& f = ::max (c, d, e);
    cout << f << endl;
    char const* g = "12", *h = "123",*i = "1234";
    ::max (g, h, i);
    cout << f << endl;
    return 0;
}

暂时就是这些了...

时间: 2024-10-10 14:39:24

C++STL - 函数模板的相关文章

快速排序函数模板

这段时间对STL比较痴迷,遂做了些许研究,今天把原来写过的快速排序算法用模板函数重新写了一下,把代码贴出来分享一下 有两个版本,版本二可以传入比较器,自己定义排序规则 快速排序算法思路: 1)从序列中选出一个元素作为基准: 2)重排序列,所有比基准小的元素位于基准左侧,比基准大的元素位于基准右侧,和基准相等的元素位于任意一侧,此过程称为分组: 3)以递归的方式对小于基准的分组和大于基准的分组分别进行排序. #include <vector> #include <list> //打印

Effective C++ 条款45 运用成员函数模板接受所有兼容类型

1. "智能指针"是行为像指针的对象,但它们能提供指针没有的功能:shared_ptr,weak_ptr,auto_ptr(见条款13)实现对堆内存的自动管理,STL的迭代器实现对整个容器的遍历等. 真正的指针的优势在于支持继承层次中派生类指针向基类指针的转换(当然标准库shared_ptr,weak_ptr,auto_ptr等已实现). 2. 由于同一template的不同具现体之间没有直接联系,也就是说对于自定义的智能指针(假设名为SmartPtr),如果不额外采取手段支持基层层次

读书笔记 effective c++ Item 45 使用成员函数模板来接受“所有兼容类型”

智能指针的行为像是指针,但是没有提供加的功能.例如,Item 13中解释了如何使用标准auto_ptr和tr1::shared_ptr指针在正确的时间自动删除堆上的资源.STL容器中的迭代器基本上都是智能指针:当然,你不能通过使用“++”来将链表中的指向一个节点的内建指针移到下一个节点上去,但是list::iterator可以这么做. 1. 问题分析——如何实现智能指针的隐式转换 真正的指针能够做好的一件事情是支持隐式转换.派生类指针可以隐式转换为基类指针,指向非const的指针可以隐式转换成为

C++学习之模板 ----函数模板、类模板

本博文主要讨论函数模板与类模板以及其简单应用. 1).作用:函数模板和类模板都可以看做是一种代码产生器,往里面放入具体的类型,得到具体化的函数或者class. 2).编译(分为两步): a):实例化之前,先检查模板本身语法是否正确: b):根据 函数调用或者类模板调用 ,先去实例化模板代码,产生具体的函数/类. 也就是说, 没有函数调用或者类类型对象声明,就不会实例化模板代码,在目标文件obj中找不到模板的痕迹. 3):优缺点 模板的缺点是代码膨胀,编译速度慢,而优点是运行速度快. 一.函数模板

STL 队列模板实现

C++ Prime确实有点难啊!看了好久都没弄清楚,一点点慢慢来. #include <iostream> #include <string> #include <cstdio> template <class Type> class Queue; //function template declaration must precede friend declaration in QueueItem template <class T> std:

模板(1)函数模板

1.引入 如何编写一个通用加法函数?第一个方法是使用函数重载, 针对每个所需相同行为的不同类型重新实现这个函数.C++的这种编程机制给编程者极大的方便,不需要为功能相似.参数不同的函数选用不同的函数名,也增强了程序的可读性.简单示例: 1 int Add(const int &_iLeft, const int &_iRight) 2 { 3 return (_iLeft + _iRight) ; 4 }f 5 loat Add(const float &_fLeft, const

函数模板与模板函数及模板类与模板的特化

函数模板( Function templates) * 模板(Templates)使得我们可以生成通用的函数,这些函数能够接受任意数据类型的参数,可返回任意类型的值,而不需要对所有可能的数据类型进行函数重载.这在一定程度上实现了宏(macro)的作用.它们的原型定义可以是下面两种中的任何一个: template <class identifier> function_declaration; template <typename identifier> function_decla

制作函数模板静态库

C++模板的学习会遇到各种各样的问题,对于一个某种程度上的新手而言,难免会碰到一些问题.但泛型编程拥有着“双拳敌四手”的绝妙心法,威风八面,实在也让自己按捺不住.前些天自己一次对reverse模板的实现过程让自己体会到解决问题的乐趣,所以如今每每遇到问题就会尝试着去探个究竟,有时候自觉也陷落于诸多语法的细枝末节当中,好在学习模板当前仅是一项技术积累,并无工程进度要求,所以暂且细细为之. 1. 起因 equal, search, find, find_if, copy, remove_copy,

函数模板的使用说明

/* * 函数模板 * 当调用某个函数时,就要以某种方式传递类型给这个函数.那么就能够使用一个函数定义替换前面额全部这些函数定义了. * 模板就能够做到这一点: * 模板机制是重要的强大的.而且如我们说提到的,在C++的标准模板库(STL)中从头到尾都在是使用它. * 模板使得类和函数不仅能通过形參接收要被存储和处理的数据值.还能够通过形參接收数据的类型.因此这 * 提供了一种编写通用和易于重用的代码的方法.由于模板定义能够用来创建一个类或函数的多个实例, * 每一个实例都能够存储和处理一种不同