You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Case 1 : ParamType是一个指针或者引用,但不是universal reference
如果expr是一个引用,忽略其引用部分。
比较expr与ParamType的类型来决定T的类型。
T&
template<typename T>
voidf(T& param); // param is a reference
......
int x = 27; // x is an intconstint cx = x; // cx is a const intconstint& rx = x; // rx is a reference to x as a const int// call ff(x); // T is int, param's type is int&f(cx); // T is const int, param's type is const int&f(rx); // T is const int, param's type is const int&
template<typename T>
voidf(const T& param); // param is now a ref-to-const
......
int x = 27; // as beforeconstint cx = x; // as beforeconstint& rx = x; // as before
......
f(x); // T is int, param's type is const int&f(cx); // T is int, param's type is const int&f(rx); // T is int, param's type is const int&
T*
改为指针也一样:
template<typename T>
voidf(T* param); // param is now a pointer
......
int x = 27;
constint *px = &x;
f(&x); // T is int, param's type is int*f(px); // T is const int, param's type is const int*
Case 2 : ParamType是Universal Reference
如果expr是左值,那么T和ParamType会被推断为左值引用。
如果expr是右值,那么就是Case 1的情况。
template<typename T>
voidf(T&& param); // param is now a universal reference
......
int x = 27;
constint cx = x;
constint& rx = x;
调用:
f(x); // x is lvalue, so T is int&, param's type is also int&f(cx); // cx is lvalue, so T is const int&, param's type is also const int&f(rx); // rx is lvalue, so T is const int&, param's type is also const int&f(27); // 27 is rvalue, so T is int, param's type is therefore int&&
template<typename T>
voidf(T param); // param is now passed by value
这意味着,param是一个被拷贝的全新对象,也就是param决定着T的类型:
如果expr是引用类型,忽略。
如果expr带有const、volatile,忽略。
int x = 27;
constint cx = x;
constint& rx = x;
f(x); // T's and param's types are both intf(cx); // T's and param's types are again both intf(rx); // T's and param's types are still both int
constchar name[] = "J. P. Briggs"; // name's type is const char[13]constchar * ptrToName = name; // array decays to pointer
在普通函数中,函数形参为数组类型和指针类型是等价的:
voidmyFunc(int param[]);
voidmyFunc1(int* param); // same function as above
但是数组作为模板参数是比较特殊的一种情况。
ParamType按值传递
template<typename T>
voidf(T param); // template with by-value parameter
......
constchar name[] = "J. P. Briggs"; // name's type is const char[13]f(name); // name is array, but T deduced as const char*
这种情况下,T被推断为指针类型const char*.
ParamType为引用类型
template<typename T>
voidf(T& param);
......
constchar name[] = "J. P. Briggs"; // name's type is const char[13]f(name); // pass array to f
voidsomeFunc(int, double); // someFunc is a function;type is void(int, double)template <typename T> voidf1(T param); // in f1, param passed by valuetemplate <typename T> voidf2(T ¶m); // in f2, param passed by reff1(someFunc); // param deduced as ptr-to-func; type is void (*)(int, double)f2(someFunc); // param deduced as ref-to-func; type is void (&)(int, double)
不过这在平时应用中也没有太大差别。
(完)
朋友们可以关注下我的公众号,获得最及时的更新:
The text was updated successfully, but these errors were encountered:
首先我们定义一下本文通用的模板定义与调用:
在编译阶段使用
expr
来推断ParamType
和T
这两个类型。这两个类型通常不同,因为ParamType
会有const
和引用等修饰。例如:这里,T被推断成
int
,但是ParamType
的类型是const T&
。直觉下
T
的类型应该和expr
的一样,比如上面的例子中,expr
和T
的类型都是int
。但是会有一些例外情况:T
的类型不仅依赖expr
,还依赖ParamType
。总共分为三大类:ParamType
是一个指针或者引用,但不是universal reference
(或者叫forwarding references
).ParamType
是一个universal reference
。ParamType
既不是指针也不是引用。Case 1 : ParamType是一个指针或者引用,但不是universal reference
expr
是一个引用,忽略其引用部分。expr
与ParamType
的类型来决定T
的类型。T&
上面例子是左值引用,但是这点对右值引用也适用。
注意第三点,
const
修饰符依旧保留。 这和普通函数的类似调用有区别:const T&
如果给
ParamType
加上const
,情况也没有太大变化:T*
改为指针也一样:
Case 2 : ParamType是Universal Reference
expr
是左值,那么T
和ParamType
会被推断为左值引用。expr
是右值,那么就是Case 1的情况。调用:
如果之前了解过完美转发和折叠引用的概念,结合Case1,这一个规则还是比较好理解的。
注意区别Universal Reference与右值引用
这两点需要区分清楚,比如:
有一个通用规则 :
universal reference
会有类型推断的过程。具体在后面的单独文章会讲,跟这篇文章的主题关系不大,这里稍微提一下 : )Case 3 : ParamType既不是指针也不是引用
这种情况就是pass-by-value的情况:
这意味着,param是一个被拷贝的全新对象,也就是param决定着T的类型:
expr
是引用类型,忽略。expr
带有const、volatile,忽略。忽略const和volatile也比较好理解:参数是值拷贝,所以形参和实参其实是互相独立的。正如下面代码可以将
const int
传递给int
,但是声明为引用则不行:注意忽略的const是针对参数本身的,而不针对指针指向的const对象:
这个按照值传递的是ptr,所以ptr的const会被忽略,但是ptr指向的对象依然是const。
数组作为参数
数组类型和指针类型是两种类型,但是有时候他们是可以互换的,比如在下面这种情况下,数组会decay成指针:
在普通函数中,函数形参为数组类型和指针类型是等价的:
但是数组作为模板参数是比较特殊的一种情况。
ParamType按值传递
这种情况下,
T
被推断为指针类型const char*
.ParamType为引用类型
现在
T
被推断为数组类型const char [13]
,ParamType
为const char (&)[13]
,这种情况是很特殊的,要与ParamType
按值传递区分开。我们可以利用上面这种特性定义一个模板来推断数组的大小,这种用法还蛮常见的:
函数作为参数
上面讨论的关于数组的情况同样适用于函数作为参数,函数类型同样也可以
decay
成函数指针:不过这在平时应用中也没有太大差别。
(完)
朋友们可以关注下我的公众号,获得最及时的更新:
The text was updated successfully, but these errors were encountered: