L7.Template
约 841 个字 124 行代码 预计阅读时间 4 分钟
Template Functions¶
If we want to compare two numbers,we may have a my_min
function:
But what if we want to compare two strings?We may write another function my_min_string
.But what if comapring two double
s?We don't want to write a my_min_double
function again.That bothers.
So oen way is to use overloaded functions:
C++ | |
---|---|
But this way also has a problem: how do you handle user defined types?
We now have a generic function!
Declaration
template
declares the next declaration is a template.
<typename T>
specifies T is some arbitrary type.
When you call a template function,either:
- for explicit instantiation,compiler finds the relevant templates and creates that function in the executable.
- for implicit instantiation,compiler looks at all possilbe overloads (template and non-template),picks the best one,deduces the template parameters,and creates the function in the executable.
- After instantiation,compiler looks as if you had written the instantiated version of the function yourself.
Template functions are note functions
It's a recipe for generating functions via instantiation.
Distinction is important for separate compilation.
Variadic Templates¶
In the above example,we can only compare two numbers.But what if we want to compare more than two numbers?
We can write a recursive version of the function which accepts a vector.
C++ | |
---|---|
But a more elegant way is to use variadic templates.
可变参数模版
一个可变参数模版就是一个接受可变数目参数的模版函数或模版类.可变数目的参数被称为参数包(parameter packet).存在两种参数包:模版参数包(template parameter packet),表示零个或多个模版参数;函数参数包(function parameter packet),表示零个或多个函数参数.
- C++ Primer 中文 第5版 第618页
C++ | |
---|---|
- Args 是一个模版参数包;rest是一个函数参数包
- Args 表示零个或多个模版类型参数
- rest 表示零个或多个函数参数
上边的代码声明了foo
是一个可变参数函数模版,它有一个名为T
的类型参数,和一个名为Args
的模版参数包.这个包表示零个或多个额外的类型参数.foo
的函数参数列表包含一个const &
类型的参数,指向T
的类型,还包含一个名为rest
的函数参数包,此包表示零个或多个函数参数.
编译器从函数的实参推断模版参数类型.对于一个可变参数模版,编译器还会推断包中参数的数目.如,给定下边调用:
C++ | |
---|---|
编译器会实例化出四个不同版本
C++ | |
---|---|
The type do not have to be homogenous.For example:
C++ | |
---|---|
Concept Lifting¶
A predicate is a function which takes in some number of arguments and returns a boolean.
C++ | |
---|---|
Then we can call this function with a predicate.
C++ | |
---|---|
What if we want to change the limit?
Here our function only compares with 5,what if we want to compare with other numbers?
One direct way is to write a new function for each number.But that's not a good idea.
So lambda functions are introduced.
Lambda Functions¶
Old approach:function pointers
C++ | |
---|---|
New approach:lambda functions
C++ | |
---|---|
Lambda Functions
auto
because we don't know the type[limit]
is capture clause,giving access to outside variables(auto val)
is the parameter list-> bool
is the return type,optional- Accessible variables inside lambda limited to capture clause and parameter list.
Note
We can ignore the parameter list and return type if they are not needed.
C++ | |
---|---|
You can also capture by reference.
C++ | |
---|---|
You can also capture everything by value or reference.
C++ | |
---|---|
显式捕获与隐式捕获
以下内容来自C++ Primer 中文 第5版 第351页
显式捕获顾名思义,直接在方括号中指定要捕获的变量,并且可以指定捕获方式(引用或值).
除了显式捕获之外,还可以让编译器根据lambda体中的代码来推断我们需要使用哪些变量.为了指示编译器推断捕获列表,应在捕获列表中写一个&
或=
.&
告诉编译器采用捕获引用方式,=
则表示采用值捕获方式.
显式捕获和隐式捕获可以混合使用,&
和=
之间也可以混合使用.
Implicit Interfaces¶
C++ | |
---|---|
Each template parameter must have the operations the function assumes it has.
- InputIt must support
- copy assignment (
iter = begin
) - prefix operator (
++iter
) - comparable to end (
begin != end
) - dereference (
*iter
) - DataType must support
- comparable to
*iter
Associative containers have an implicit interface:the type must support the <
operator.
C++ | |
---|---|
Overload resolution¶
What if there are multiple potential templates functions?
- From all functions within scope,look up all functions that match the name of function call.Iif template is found,deduce the type.
- From all candidate functions,check the number and types of the parameters.For template instantiations,try substituting and see if implicit interface satisfied.If fails,remove these instantiations.
- From all viable functions,rank the viable functions based on the type conversions necessary and the priority of various template types.Choose the best function.
Summary
查找匹配的函数,然后检查函数的参数数量以及类型,再对所有符合条件的函数排序,选择最佳函数.
SFINAE
- Substitution Failure Is Not An Error
- When substituting the deduced types fails(in the immdeiate context) because the type doesn't satisfy implicit interfaces,this does not result in a compile error.
- Instead,the template is removed from the list of viable functions.
Here are some SFINAE examples:
Example
So from the above examples we can see that,SFNIAE removes the overloads which do not compile,allowing you to call printSize on different types.