当前位置:网站首页>Function templatesfunction templates
Function templatesfunction templates
2022-06-12 02:25:00 【loongknown】
Function templates Function Templates
- A glimpse of function templates A First Look at Function Templates
- Template parameter derivation Template Argument Deduction
- Multiple template parameters Multiple Template Parameters
- Default template parameters Default Template Arguments
- Function template overload Overloading Function Templates
- summary Summary
- Reference resources Reference
Start with this article , Yes C++ Templates The Complete Guide Second Edition Carry out systematic learning and interpretation .
This chapter explains the basic knowledge of template functions in Chapter 1 , The following chapters will go deeper .
A glimpse of function templates A First Look at Function Templates
A function template represents a family of functions , Some of its elements are parameterized .
Define function templates Defining the Template
template<typename T>
T max (T a, T b) {
return b < a ? a : b;
}
The template function returns the maximum of the two input parameters , Two input parameters a and b The type of is template parameter T. Template parameters are declared in the following syntax :
template< comma-separated-list-of-parameters >
here , keyword typename Used to define template parameters . For historical reasons , You can also use keywords class Instead of typename To define template parameters . stay C++98 It used to be class Declare template parameters ,C++98 Introduced typename, To stay compatible , Either . therefore , The above code is equivalent to :
template<class T>
T max (T a, T b) {
return b < a ? a : b;
}
however , To avoid and classes (class) The definition of , Recommended priority typename Define template type parameters .
In our example, the template parameter is T, Use T It is just a convention , You can also use other identifiers , for example U. The template parameters here can be of any type , As long as this type satisfies the operation of the template function . In the example above , type T Must support < operation . Besides , A less obvious limitation is : To be returned by the function ,T The value of type must be copyable .
Using function templates Using the Template
int main()
{
int i = 42;
std::cout << "max(7,i): " << ::max(7,i) << ’\n’; // 42
double f1 = 3.4;
double f2 = -6.7;
std::cout << "max(f1,f2): " << ::max(f1,f2) << ’\n’; // 3.4
std::string s1 = "mathematics";
std::string s2 = "math";
std::cout << "max(s1,s2): " << ::max(s1,s2) << ’\n’; // mathematics
return 0;
}
Use here ::max Call function max Avoid confusion , Is to find in the global namespace max, Because this function is also defined in the standard library std::max.
Function calls with different parameter types will produce different function instances . The above examples generate int 、double and std::string 3 Instances of versions . for example ::max(7,i) , The compiler will generate parameters of type int Function instance of , Similarly, call the following code :
int max (int a, int b) {
return b < a ? a : b;
}
Be careful ,void It is also a valid template parameter type . for example :
template<typename T>
T foo(T*) {
}
void* vp = nullptr;
foo(vp); // OK: deduces void foo(void*)
A two-stage translation process Two-Phase Translation
Using parameter types that are not supported by operations in the template will generate compilation errors . for example :
std::complex<float> c1, c2; // doesn’t provide operator <
...
::max(c1,c2); // ERROR at compile time
Template translation / Compilation is divided into two stages : Occurs before and during instantiation respectively .
- Check the code template code before instantiation , The template parameters are ignored . It mainly includes :
- Whether there are grammatical errors . For example, whether semicolons are missing .
- Whether to use unknown names that do not depend on template parameters ( Function name 、 Type name, etc ).
- Check for... That do not depend on template parameters static assert.
- Check the template code again during instantiation , In particular, the parts that depend on template parameters . For example, whether the instantiated parameter type in the above example supports
<operation .
template <typename T>
void f(T x) {
undeclared(); // first-phase compile-time error if undeclared() unknown
undeclared(x); // second-phase compile-time error if undeclared(T) unknown
static_assert(sizeof(int) > 10,
"int too small"); // always fails if sizeof(int) <= 10
static_assert(sizeof(T) > 10,
"T too small"); // fails if instantiated for T with size <= 10
}
Template parameter derivation Template Argument Deduction
When we call a template function with parameters ( such as max()), The template parameters are determined by the parameters we pass . If we pass two int Give template functions , The compiler will derive T by int.
in addition ,T May be part of the type . for example , We use constant references to declare max():
template<typename T>
T max (T const& a, T const& b) {
return b < a ? a : b;
}
We pass on two again int Give this template function ,T It is also deduced as int.
Type conversion in type derivation :
- When invoking a parameter through a reference declaration , There will be no type conversion during type pushing , The two are declared as the same template parameters
TThe parameters of must match exactly . for example :
#include<iostream>
template <typename T>
T max(T& a, T& b) {
return b < a ? a : b;
}
int main() {
const int a = 3;
int b = 4;
std::cout << ::max(a, b) << std::endl;
return 0;
}
The compilation error is as follows :
hello.cpp: In function ‘int main()’:
hello.cpp:11:28: error: no matching function for call to ‘max(const int&, int&)’
11 | std::cout << ::max(a, b) << std::endl;
| ^
hello.cpp:4:3: note: candidate: ‘template<class T> T max(T&, T&)’
4 | T max(T& a, T& b) {
| ^~~
hello.cpp:4:3: note: template argument deduction/substitution failed:
hello.cpp:11:28: note: deduced conflicting types for parameter ‘T’ (‘const int’ and ‘int’)
11 | std::cout << ::max(a, b) << std::endl;
| ^
- When a call parameter is declared by value , Only degradation is supported (decay) Type conversion of :cv(const and volatile) Be ignored , The reference is converted to the referenced type , Convert the original array and function to the corresponding pointer type . The two are declared as the same template parameters
TThe degenerate type of the parameter of must match . for example :
template<typename T>
T max (T a, T b);
...
int i = 5;
int const c = 42;
max(i, c); // OK: T is deduced as int
max(c, c); // OK: T is deduced as int
int& ir = i;
max(i, ir); // OK: T is deduced as int
int arr[4];
foo(&i, arr); // OK: T is deduced as int*
But the following example has a problem :
max(4, 7.2); // ERROR: T can be deduced as int or double
std::string s;
foo("hello", s); // ERROR: T can be deduced as char const[6] or std::string
The solutions to the above two examples are as follows :
- Show cast .
max(static_cast<double>(4), 7.2); // OK - Show specifying template parameters to prevent compiler type derivation .
max<double>(4, 7.2); // OK - Use two different types of template parameters .
Function default call parameter type derivation :
Function default call parameters cannot derive type . Look at an example :
template<typename T>
void f(T = "");
...
f(1); // OK: deduced T to be int, so that it calls f<int>(1)
f(); // ERROR: cannot deduce T
To solve this problem , The default type of template parameter needs to be declared .
template<typename T = std::string>
void f(T = "");
...
f(); // OK
Multiple template parameters Multiple Template Parameters
You can specify the number of template parameters as needed . for example :
template<typename T1, typename T2>
T1 max (T1 a, T2 b) {
return b < a ? a : b;
}
...
auto m = ::max(4, 7.2); // OK, but type of first argument defines return type
Grammatically , There is no problem with the above code . Just use one of the template parameters as the return type , Then change the calling order of the next two variables , You will get different results . Pass on 66.66 and 42 to max obtain double Type of 66.66, And deliver 42 and 66.66 to max obtain int Type of 66.
C++ There are different ways to solve the above problems :
- Introduce the first 3 Template parameters as return types .
- Let the compiler deduce the return type .
- A public type that uses two parameters (common type) As return type .
Next, discuss the above methods respectively .
Return template parameters of value type Template Parameters for Return Types
When a template function is called , We can display the specified template parameter type , Or not ( Let the compiler deduce ). however , When there is no connection between the call parameter and the template parameter , You must display the specified template parameters when calling the template function .
template<typename T1, typename T2, typename RT>
RT max (T1 a, T2 b);
In this case , The compiler's parameter derivation cannot handle the type of the return value ,RT Nor does it appear in the function call parameters , therefore RT Cannot be deduced . You must display the specified template parameter type :
::max<int,double,double>(4, 7.2); // OK, but tedious
Usually , You must specify all parameter types until the last parameter that cannot be implicitly derived . For this example , We can adjust the parameter position of the return value type template , In this way, we can only specify the type of return value when calling the function , Other template parameters are left to the compiler to derive .
template<typename RT, typename T1, typename T2>
RT max (T1 a, T2 b);
...
::max<double>(4, 7.2) // OK: return type is double, T1 and T2 are deduced
Derive the return value type Deducing the Return Type
If the return value type depends on the template parameter , The best way is to leave it to the compiler to deduce .C++14 You can use it directly auto As return value type .
template<typename T1, typename T2>
auto max (T1 a, T2 b) {
return b < a ? a : b;
}
The trailing return type is not used here (trailing return type) Indicates that the return value type can be derived from the return value statement in the function body . stay C++11 in , You need to use the trailing return value type declaration :
template<typename T1, typename T2>
auto max (T1 a, T2 b) -> decltype(b<a?a:b) {
return b < a ? a : b;
}
The type of the return value is determined by the question mark expression b<a?a:b Type to confirm . If a and b Different types of ,decltype(b<a?a:b) Will return the common types of both (common type). For the return type of question mark expression, please refer to Conditional Operator: ? : , For public types, please refer to std::common_type .
therefore , The condition of the question mark expression is not important here , You can use it directly true Instead of :
template<typename T1, typename T2>
auto max (T1 a, T2 b) -> decltype(true?a:b);
then , The above code has another flaw : The type of the return value may be a reference type , Because under some conditions T It could be a reference . Therefore, the following modifications are required :
#include <type_traits>
template<typename T1, typename T2>
auto max (T1 a, T2 b) -> typename std::decay<decltype(true?a:b)>::type
{
return b < a ? a : b;
}
there type Is a member type , Keyword required typename To embellish .
The return type is a generic type Return Type as Common Type
C++11 The standard library provides std::common_type<>::type Produce two ( Or more ) Public type of type (common type). therefore , We can use std::common_type<>::type Specify the return value type of the template function :
#include <type_traits>
template<typename T1, typename T2>
typename std::common_type<T1,T2>::type max (T1 a, T2 b) {
return b < a ? a : b;
}
C++14 To simplify the trait Library usage , Directly in trait name After add _t suffix . The above return value type can be simplified to :
std::common_type_t<T1,T2> // equivalent since C++14
Default template parameters Default Template Arguments
We can define the default values of template parameters . Take the example above , We can define max Return value type of RT, And its default value is defined as T1 and T2 Of common_type, Use the question mark expression to achieve the following :
#include <type_traits>
template<typename T1, typename T2,
typename RT = std::decay_t<decltype(true ? T1() : T2())>>
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}
Be careful : The above implementation , We need to be able to call the default constructor of the incoming type . namely T1 and T2 There must be a default constructor . for example :
#include <type_traits>
class A {
public:
A() = default;
A(int a): x(a) {
}
bool operator< (const A& a) {
return this->x < a.x;
}
private:
int x;
};
template<typename T1, typename T2,
typename RT = std::decay_t<decltype(true ? T1() : T2())>>
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}
int main()
{
A a(2), b(3);
auto c = ::max(a, b);
return 0;
}
If you will A() = default; Comment out , be A There is no default constructor , The default parameter type derivation of the template fails .
main.cpp:15:44: error: no matching function for call to 'A::A()'
15 | typename RT = std::decay_t<decltype(true ? T1() : T2())>>
You can also use std::common_type Specify the public type of the default template parameter :
#include <type_traits>
template<typename T1, typename T2,
// typename RT = typename std::common_type<T1,T2>::type> // C++11
typename RT = std::common_type_t<T1,T2>> // C++14
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}
We can use the default template parameter as the return value type , You can also specify the return value type :
auto a = ::max(4, 7.2);
auto b = ::max<double,int,long double>(7.2, 4);
As described earlier , We can adjust the default template parameter position to the first one , In this way, you can only specify the return value type when calling , Other template parameter types are left to the compiler to derive .
template<typename RT = long, typename T1, typename T2>
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}
int i;
long l;
...
max(i, l); // returns long (default argument of template parameter for return type)
max<int>(4, 42); // returns int as explicitly requested
Function template overload Overloading Function Templates
Like a normal function , Function templates can also be overloaded . for example :
// maximum of two int values:
int max (int a, int b)
{
return b < a ? a : b;
}
// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
return b < a ? a : b;
}
int main()
{
::max(7, 42); // calls the nontemplate for two ints
::max(7.0, 42.0); // calls max<double> (by argument deduction)
::max('a', 'b'); // calls max<char> (by argument deduction)
::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
}
C++ Matching principle of overloaded functions : If the function instantiated by the template matches the ordinary overloaded function exactly , Ordinary overloaded functions are preferred , Secondly, select the exact version instantiated by the template function . For this, please refer to my previous blog Item 26: Avoid overloading on universal references. .
about ::max(7, 42); Both normal functions and template functions can be matched , Match ordinary functions first . about ::max(7.0, 42.0) Will match to the template function .
Of course, you can also specify an empty template parameter list , Used to indicate that the calling function template is not a normal function :
::max<>(7, 42); // calls max<int> (by argument deduction)
The parameters of ordinary functions can be automatically typed , Function templates do not . So the last one calls the normal function , Both parameters are changed to int :
::max('a', 42.7); // only the nontemplate function allows nontrivial conversions
Overloaded function templates need to be guaranteed : For any call , Only one version can match , Otherwise, there will be ambiguity . for example : Overloading the return value type may cause ambiguity .
template<typename T1, typename T2>
auto max (T1 a, T2 b)
{
return b < a ? a : b;
}
template<typename RT, typename T1, typename T2>
RT max (T1 a, T2 b)
{
return b < a ? a : b;
}
auto a = ::max(4, 7.2); // uses first template
however ,auto b = ::max<long double>(7.2, 4); Then both versions can match , Cause compilation error :
main.cpp:17:33: error: call of overloaded 'max<long int, double>(int, double)' is ambiguous
17 | auto c = ::max<long, double>(4, 7.2);
| ~~~~~~~~~~~~~~~~~~~^~~~~~~~
main.cpp:4:6: note: candidate: 'auto max(T1, T2) [with T1 = long int; T2 = double]'
4 | auto max (T1 a, T2 b)
| ^~~
main.cpp:9:4: note: candidate: 'RT max(T1, T2) [with RT = long int; T1 = double; T2 = double]'
9 | RT max (T1 a, T2 b)
Looking at a pointer and tradition C Examples of string overloading :
#include <cstring>
#include <string>
// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
return b < a ? a : b;
}
// maximum of two pointers:
template<typename T>
T* max (T* a, T* b)
{
return *b < *a ? a : b;
}
// maximum of two C-strings:
char const* max (char const* a, char const* b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
int main ()
{
int a = 7;
int b = 42;
auto m1 = ::max(a,b); // max() for two values of type int
std::string s1 = "hey";
std::string s2 = "you";
auto m2 = ::max(s1,s2); // max() for two values of type std::string
int* p1 = &b;
int* p2 = &a;
auto m3 = ::max(p1,p2); // max() for two pointers
char const* x = "hello";
char const* y = "world";
auto m4 = ::max(x,y); // max() for two C-strings
}
It is generally recommended to use function templates that pass values , If the template function passed to the reference is implemented , Reload the transmission C String value version , Can lead to mistakes :
#include <cstring>
// maximum of two values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b)
{
return b < a ? a : b;
}
// maximum of two C-strings (call-by-value)
char const* max (char const* a, char const* b)
{
return std::strcmp(b,a) < 0 ? a : b;
}
// maximum of three values of any type (call-by-reference)
template<typename T>
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 ()
{
char const* s1 = "frederic";
char const* s2 = "anica";
char const* s3 = "lucas";
auto m2 = ::max(s1, s2, s3); // run-time ERROR
}
max(max(a, b), c) in ,max(a, b) A reference to a temporary object is generated , This temporary reference is in return max (max(a,b), c); The end of the statement is invalid , Causes the reference to hang :
main.cpp: In instantiation of 'const T& max(const T&, const T&, const T&) [with T = const char*]':
main.cpp:24:17: required from here
main.cpp:17:20: warning: returning reference to temporary [-Wreturn-local-addr]
17 | return max (max(a,b), c); // error if max(a,b) uses call-by-value
| ~~~~^~~~~~~~~~~~~
bash: line 7: 2907 Segmentation fault (core dumped) ./a.out
Besides , The overloaded version needs to be declared before calling , Otherwise, it may produce unexpected results . for example :
#include <iostream>
// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
std::cout << "max<T>() \n";
return b < a ? a : b;
}
// maximum of three values of any type:
template<typename T>
T max (T a, T b, T 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:
int max (int a, int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
int main()
{
::max(47,11,33); // OOPS: uses max<T>() instead of max(int,int)
}
Besides ,C++11 have access to constexpr Function to generate compile time values .
template <typename T, typename U>
constexpr auto max(T a, U b) {
return b < a ? a : b;
}
int a[::max(sizeof(char), 1000u)];
std::array<int, ::max(sizeof(char), 1000u)> b;
summary Summary
- Function templates define a family of functions
- The compiler can derive template parameters from the passed parameters
- You can also display the specified template parameters
- You can define default template parameters
- Function templates can be overloaded
- When reloading a template function , You need to ensure that there is only one matching version for any call
- When reloading a function template , Pay attention to the reference suspension caused by reference passing and value passing versions
- The overloaded version needs to be declared before calling
Reference resources Reference
- http://www.tmplbook.com
- https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/e4213hs1%28v=vs.110%29?redirectedfrom=MSDN
- https://en.cppreference.com/w/cpp/types/common_type
边栏推荐
- 力扣解法汇总905-按奇偶排序数组
- 微信公众号开发地理位置坐标的转换
- DDD的分层架构
- Abaqus中批量对节点施加集中力荷载
- 力扣解法汇总398-随机数索引
- 力扣解法汇总1037-有效的回旋镖
- 力扣解法汇总449-序列化和反序列化二叉搜索树
- Transformation of geographical coordinates of wechat official account development
- How should programmers solve the problem of buying vegetables? Take you hand in hand to quickly order and grab vegetables by using the barrier free auxiliary function
- No writing, please forgive me
猜你喜欢

maya前台渲染插件mel脚本工具

Master of a famous school has been working hard for 5 years. AI has no paper. How can the tutor free range?

ACL2022 | DCSR:一种面向开放域段落检索的句子感知的对比学习方法

How WPS inserts a directory and the operating steps for quickly inserting a directory

Acl2022 | DCSR: a sentence aware contrastive learning method for open domain paragraph retrieval

Smartbi helps you solve the problem of losing high-value customers

Graphical data analysis | data analysis tool map

ACL 2022 - strong combination of pre training language model and graphic model

Graphical data analysis | business analysis and data mining

The program actively carries out telephone short message alarm, and customizes telephone, short message and nail alarm notifications
随机推荐
Intel case
BaseDexClassLoader那些事
How to make div 100% page (not screen) height- How to make a div 100% of page (not screen) height?
博创智能冲刺科创板:年营收11亿 应收账款账面价值3亿
2022 Fujian Provincial Safety Officer C certificate (full-time safety officer) examination simulation 100 questions and answers
Force deduction solution summary 1037- effective boomerang
程序员应该如何解决买菜难问题?手把手带你利用无障碍辅助功能快速下单抢菜
力扣解法汇总417-太平洋大西洋水流问题
Xcall cluster script (view JPS command)
SQL calculates KS, AUC, IV, psi and other risk control model indicators
UE4\UE5触摸屏touch事件:单指、双指
Force deduction solution summary interview question 17.11- word distance
Force deduction solution summary - Sword finger offer II 114 Alien dictionary
Ozzanmation action system based on SSE
Several common instructions for virsh to create / shut down / stop virtual machines
Summary of force deduction method 417- Pacific Atlantic current problems
力扣解法汇总450-删除二叉搜索树中的节点
2022福建省安全员C证(专职安全员)考试模拟100题及答案
Force deduction solution summary 473 match to square
一起教育科技单季营收2.3亿:同比降51% 净亏大幅收窄