templates(1.2)

max.hpp


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
template <typename T>
inline T const& max (T const& a, T const& b)
{
// if a < b then use b else use a
return a < b ? b : a;
}

使用max.hpp


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <iostream>
#include <string>
#include "max.hpp"
int main()
{
int i = 42;
std::cout << "max(7,i): " << ::max(7,i) << std::endl;

double f1 = 3.4;
double f2 = -6.7;
std::cout << "max(f1,f2): " << ::max(f1,f2) << std::endl;

std::string s1 = "mathematics";
std::string s2 = "math";
std::cout << "max(s1,s2): " << ::max(s1,s2) << std::endl;
}

实际上,templates 会被编译两次:

1. 不实例化,只是对 template
程序代码进行语法检查以发现诸如「缺少分号」等等的语法错误。

2. 实例化时,编译器检查 template
程序代码中的所有调用是否合法,诸如「未获支持之函数调用」便会在这个阶段被检查出来。

这会导致一个严重问题:当 function template 被运用而引发实例化过程时,某些时候编译器需要用到template
的原始定义。一般情况下,对普通的(non-template)functions而言,编译和链接两步骤是各自独立的,编译器只检查各个functions的声明语句是否和调用语句相符,然而template
的编译破坏了这个规则。

2.2
自变量推导(Argument Deduction)

当我们使用某一类型的自变量调用 max()时,template parameters 将以该自变量类型确定下来。

如果 我们针对参数类型 T const& 传递两个 ints,编译器必然能够推导出 T 是int。注意这里并不允许「自动类型转换」。是的,每个T
都必须完全匹配其自变量。例如:


template <typename T>
inline T const& max(T const& a, T const& b);
...
max(4, 7); // OK,两个 T 都被推导为 int
max(4, 4.2); // 错误:第一个 T 被推导为 int,第二个 T 被推导为 double

有三种方法可以解决上述问题:


1. 把两个自变量转型为相同类型:

max(static_cast<double>(4), 4.2); // OK

2. 明确指定 T 的类型:

max<double>(4, 4.2); // OK

3. 对各个 template parameters 使用不同的类型(译注:意思是不要像上面那样都叫做 T)。

下一节详细讨论这些问题。

2.3
Template Parameters( 模 板参 数 )

Function templates 有两种参数:

1. Template parameters(模板参数),在function template
名称前的一对角(尖)括号中声明:


template <typename T> // T 是个 template parameter

2. Call parameters(调用参数),在 function template
名称后的小(圆)括号中声明:


... max (T const& a, T const& b); // a 和 b 是调用参数

template parameters 的数量可以任意,但你不能在 function
templates 中为它们指定预设自变量值(这一点与 class templates 不同)。例如你可以在 max()template
中定义两个不同类型的调用参数:


template <typename T1, typename T2>
inline T1 max (T1 const& a, T2 const& b)
{
  return a < b ? b : a;
}
...
max(4, 4.2); // OK。返回类型和第一自变量类型相同

这似乎是一个可以为 max()template
的参数指定不同类型的好办法,但它也有不足。问题在于你必须声明返回值的类型。如果你使用了其中一个类型,另一个类型可能被转型为该类型。C++
没有提供一个机制用以选择「效力更大的类型, the more powerful
type
」(然而你可以藉由某些巧妙的template 编程手段来提供这种机制,参见
15.2.4 节)。因此,对于42和66.66两个调用自变量,max()的返回值要么是double 66.66,要么是int 66。另一个缺点是,把第二参数转型为第一参数的类型,会产生一个局部临时对象(local
temporary object),因而无法以by reference 方式传回结果。因此在本例之中,返回类型必须是 T1,不能是 T1
const&。

由于call parameters 的类型由template parameters
建立,所以两者往往互相关联。我们把这种概念称为 function template argument
deduction(函数模板自变量推导)。它使你可以像调用一个常规(意即 non-template)函数一样来调用 function template。

然而正如先前提到的那样,你也可以「明确指定类型」来实例化一个 template:


template <typename T>
inline T const& max (T const& a, T const& b);
...
max<double>(4,4.2); // 以 double 类型实例化 T

当template parameters和call parameters之间没有明显联系,而且编译器无法推导出template
arameters 时,你必须明确地在调用时指定template arguments。例如你可以为max()引入第三个template argument
type 作为返回类型:


template <typename T1, typename T2, typename RT>
inline RT max (T1 const& a, T2 const& b);

然而「自变量推导机制」并不对返回类型进行匹配,而且上述的RT
也并非函数调用参数(call parameters)中的一个;因此编译器无法推导出 RT。你不得不像这样明确指出 template
arguments:


template <typename T1, typename T2, typename RT>
inline RT max (T1 const& a, T2 const& b);
...
max<int,double,double>(4, 4.2);
// OK,但是相当冗长(译注:因为其实只需明写第三自变量类型,却连前两个自变量类型都得写出来)

以上我们所看到的是,要么所有function template arguments
都可被推导出来,要么一个也推导不出来。另有一种作法是只明确写出第一自变量,剩下的留给编译器去推导,你要做的只是把所
有「无法被自动推导出来的自变量类型」写出来。因此,如果把上述例子中的参数顺序改变一下, 调用时就可以只写明返回类型:


template <typename RT, typename T1, typename T2>
inline RT max (T1 const& a, T2 const& b);
...
max<double>(4,4.2); // OK,返回类型为 double

此例之中,我们调用 max()时,只明确指出返回类型RT 为double,至于T1 和T2
两个参数类型会被编译器根据调用时的自变量推导为int 和 double。注意,这些max()修改版本并没带来什么明显好处。在「单一参数」版本中,如果两个自变量的
类型不同,你可以指定参数类型和回返值类型。总之,为尽量保持程序代码简单,使用「单一参 数」的 max()是不错的主意。讨论其它 template
相关问题时,我们也会遵守这个原则。

2.4
重载(Overloading)Function Templates

就像常规(意即non-template)functions一样,function templates
也可以被重载(译注:C++标准库中的许多STL算法都是如此)。这就是说,你可以写出多个不同的函数定义,并使用相同的函数名称;当客户调用其中某个函数时,C++编译器必须判断应该调用哪一个函数。即使不牵扯templates,这个推断过程也非常复杂。本节讨论的是,一旦涉及templates,重载将是一个怎样的过程。


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
// maximum of two int values
inline int const& max (int const& a, int const& b)
{
return a < b ? b : a;
}

// maximum of two values of any type
template <typename T>
inline T const& max (T const& a, T const& b)
{
return a < b ? b : a;
}

// maximum of three values of any type
template <typename T>
inline T const& max (T const& a, T const& b, T const& c)
{
return ::max (::max(a,b), c);
}

int main()
{
::max(7, 42, 68); // calls the template for three arguments
::max(7.0, 42.0); // calls max<double> (by argument deduction)
::max(‘a‘, ‘b‘); // calls max<char> (by argument deduction)
::max(7, 42); // calls the nontemplate for two ints
::max<>(7, 42); // calls max<int> (by argument deduction)
::max<double>(7, 42); // calls max<double> (no argument deduction)
::max(‘a‘, 42.7); // calls the nontemplate for two ints
}

这个例子说明:non-template function 可以和同名的 function template
共存,也可以和其相同类型的具现体共存。当其它要素都相等时,重载解析机制会优先选择 non-template function,而不选择由 function
template 实例化后的函数实体。上述第四个调用便是遵守这条规则:


::max(7, 42); // 两个自变量都是 int,吻合对应的 non-template function

但是如果可由 template 产生更佳匹配,则 template
具现体会被编译器选中。前述的第二和第三个调用说明了这一点:


::max(7.0, 42.0); // 调用 max<double>(经由自变量推导)
::max(‘a‘, ‘b‘); // 调用 max<char>(经由自变量推导)

调用端也可以使用空的 template argument
list,这种形式告诉编译器「只从 template 具现体中挑选适当的调用对象」,所有template parameters 都自call
parameters 推导而得:


::max<>(7, 42); // 调用 max<int>(经由自变量推导)

另外,「自动类型转换」只适用于常规函数,在templates
中不予考虑,因此前述最后一个调用调用的是 non-template 函数。在该处,‘a‘ 和 42.7 都被转型为 int:


::max(‘a‘, 42.7); // 本例中只有 non-template 函数才可以接受两个不同类型的自变量

下面是一个更有用的例子,为指针类型和 C-style 字符串类型重载了 max()template:


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <iostream>
#include <cstring>
#include <string>

// maximum of two values of any type
template <typename T>
inline T const& max (T const& a, T const& b)
{
return a < b ? b : a;
}

// maximum of two pointers
template <typename T>
inline T* const& max (T* const& a, T* const& b)
{
return *a < *b ? b : a;
}

// maximum of two C-strings
inline char const* const& max (char const* const& a,
char const* const& b)
{
return std::strcmp(a,b) < 0 ? b : a;
}

int main ()
{
int a=7;
int b=42;
::max(a,b); // max() for two values of type int

std::string s="hey";
std::string t="you";
::max(s,t); // max() for two values of type std::string

int* p1 = &b;
int* p2 = &a;
::max(p1,p2); // max() for two pointers

char const* s1 = "David";
char const* s2 = "Nico";
::max(s1,s2); // max() for two C-strings
}

注意,所有重载函数都使用by reference方式来传递自变量。一般说来,不同的重载形式之间最好只存在「绝对必要的差异」。各重载形式之间应该只存在「参数个数的不同」或「参数类型
的明确不同」,否则可能引发各种副作用。举个例子,如果你以一个「by value 形式的 max()」重载一个「by reference 形式的
max()」(译注:两者之间的差异不够明显),就无法使用「三自变量」版本的
max()来取得「三个 C-style 字符串中的最大者」:


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <iostream>
#include <cstring>
#include <string>

// maximum of two values of any type (call-by-reference)
template <typename T>
inline T const& max (T const& a, T const& b)
{
return a < b ? b : a;
}

// maximum of two C-strings (call-by-value)
inline char const* max (char const* a, char const* b)
{
return std::strcmp(a,b) < 0 ? b : a;
}

// maximum of three values of any type (call-by-reference)
template <typename T>
inline T const& max (T const& a, T const& b, T const& c)
{
return max (max(a,b), c); // error, if max(a,b) uses call-by-value
}

int main ()
{
::max(7, 42, 68); // OK

const char* s1 = "frederic";
const char* s2 = "anica";
const char* s3 = "lucas";
::max(s1, s2, s3); // ERROR

}

本例中针对三个 C-style 字符串调用 max(),会出现问题。以下这行述句是错误的:


return ::max (::max(a,b), c);

因为C-style字符串的max(a,b)重载函数创建了一个新而暂时的区域值(a new,
temporary local value),而该值却以 by
reference 方式被传回(那当然会造成错误)。

这只是细微的重载规则所引发的非预期行为例子之一。当函数调用动作发生时,如果不是所有重载形式都在当前范围内可见,那么上述错误可能发生,也可能不发生。事实上,如果把「三自变量」版本的
max()写在接受两个ints的max()前面(于是后者对前者而言不可见),那么在调用「三自变量」max()时,会间接调用「双自变量」max()
function template:


/* The following code example is taken from the book
* "C++ Templates - The Complete Guide"
* by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
*
* (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
// maximum of two values of any type
template <typename T>
inline T const& max (T const& a, T const& b)
{
return a < b ? b : a;
}

// maximum of three values of any type
template <typename T>
inline T const& max (T const& a, T const& b, T const& c)
{
return max (max(a,b), c); // uses the template version even for ints
} // because the following declaration comes
// too late:
// maximum of two int values
inline int const& max (int const& a, int const& b)
{
return a < b ? b : a;
}

就目前而言,你应该遵循一条准则:总是把所有形式的重载函数写在

时间: 2024-11-09 06:48:08

templates(1.2)的相关文章

Django的第一个Templates

1.URL配置方法: myblog中的urls.py 的文件 from django.conf.urls import url,include from django.contrib import admin import blog.views as bv urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', include('blog.urls')), ] blog中创建一个urls.py文件 from django.conf

springboot 1.5.2 thymeleaf 添加templates 静态资源访问路径

从velocity 模板切换到thymeleaf 后, 默认模板位置为templates , 有时候静态资源方在该目录下会出现访问404错误 解决办法: application.properties 中添加: spring.mvc.static-path-pattern=/** spring.resources.static-locations=classpath:/templates/,classpath:/META-INF/resources/,classpath:/resources/,c

[Ember] Ember.js Templates

In this lesson, we'll go over some of the basics of Ember.js templates and how they work with controllers. Generate a controller: ember g controller hello Generate a Template: ember g template application Template syntax: application.hbs: {{#if showN

warning: templates not found

在 Mac上用 SourceTree 克隆代码的时候, 出现了 warning: templates not found /user/local/git/share/git-core/templates 警告,导致克隆失败 在终端输入 sudo mkdir /usr/local/git sudo mkdir /usr/local/git/share sudo mkdir /usr/local/git/share/git-core sudo mkdir /usr/local/git/share/g

free CSS and HTML5 site templates

http://templated.co/ 模板 A collection of 850 free CSS and HTML5 site templates, designed & built by Cherry + AJ and released under the Creative Commons https://tampermonkey.net/ Tampermonkey : Tampermonkey is a free browser extension and the most popu

【Silverlight】Templates的用法

<Button Content="A Custom Button Template" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="174,120,0,0"> <Button.Template> <ControlTemplate TargetType="Button" > <Border Bor

格式工厂(三) Variadic Templates

版权声明:本文为博主原创文章,未经博主允许不得转载. 这次主要介绍C++11的又一个新特性 Variadic Templates (可变模板参数) 它的实现类似于initializer_list<>,它可是使类模板接受一包参数 本节主要应用递归的形式介绍 Variadic  Templates 1.简单的调用 #include <iostream> #include "string" using namespace std; void printX() {}//

Django Templates

二分春色到穷阎,儿女祈翁出滞淹.幽蛰夜惊雷奋地,小窗朝爽日筛帘. 惠风全解墨池冻,清昼胜翻云笈签.亲友莫嗔情话少,向来屏息似龟蟾. 料峭寒犹薄,阴云带晚烟. 雨催惊蛰候,风作勒花开. 日永消香篆,愁浓逼酒船. 为君借余景,收拾赋新篇. 作者:小亲姐姐来源链接:http://www.qbaobei.com/jiaoyu/407464.html来源:亲亲宝贝著作权归作者所有. 料峭寒犹薄,阴云带晚烟. 雨催惊蛰候,风作勒花开. 日永消香篆,愁浓逼酒船. 为君借余景,收拾赋新篇. 作者:小亲姐姐来源链

C++模板(Templates)

模板(template)是泛型编程的基础,"泛型"的含义就是没有不依赖具体的数据类型.模板的引入是为了创建一般性的类(模板类)或者函数(模板函数).典型的容器比如迭代器/算法等是泛型编程的典型案例.例如,定义了一个vector,可以使用vector<int>, vector<string>, vector<vector>等等. 函数模板 模板函数的一般定义方式为: 这里的type可以看做是代表了一种数据类型的占位符名称, 在函数内部的定义中可以使用它

django复习笔记3:urls/views/templates三板斧

0.先看看文件结构 sh-3.2# tree -L 2 mysite/ mysite/ ├── __pycache__ │   └── manage.cpython-34.pyc ├── blog │   ├── __init__.py │   ├── __init__.pyc │   ├── __pycache__ │   ├── admin.py │   ├── admin.pyc │   ├── migrations │   ├── models.py │   ├── models.pyc