当前位置:网站首页>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
边栏推荐
- The release of star ring kundb 2.2 provides a new choice for business systems with high concurrent transactions and queries
- 力扣解法汇总824-山羊拉丁文
- Proxy and reflection (II)
- RPA introduction
- 力扣解法汇总面试题 17.11-单词距离
- maya前台渲染插件mel脚本工具
- 函数模板 Function Templates
- 力扣解法汇总868-二进制间距
- 高考完不要急着去打工了,打工以后有的是机会,不差这三个月
- Implementation scheme of iteration and combination pattern for general tree structure
猜你喜欢

Graphical data analysis | business analysis and data mining

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

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

消防栓监测系统毕业设计---论文(附加最全面的从硬件电路设计->驱动程序设计->阿里云物联网搭建->安卓APP设计)

The release of star ring kundb 2.2 provides a new choice for business systems with high concurrent transactions and queries

BaseDexClassLoader那些事

UE4\UE5触摸屏touch事件:单指、双指

Maya foreground rendering plug-in Mel scripting tool

Apply concentrated load to nodes in batch in ABAQUS

SQL calculates KS, AUC, IV, psi and other risk control model indicators
随机推荐
没有文笔,大家多多包涵
力扣解法汇总面试题 01.05. 一次编辑
ozzanimation-基于sse的动作系统
Force deduction solution summary 883- projected area of 3D shape
DDD的分层架构
Does the virtual host have independent IP
2022西式面点师(技师)复训题库及在线模拟考试
El upload upload file
力扣解法汇总668-乘法表中第k小的数
Force deduction solution summary 1022- sum of binary numbers from root to leaf
Force deduction solution summary 699- dropped blocks
Don't miss it! Five large data visualization screens that HR must collect
How to use DAO to build a knowledge database with collective wisdom and sustainable incentive mechanism
力扣解法汇总965-单值二叉树
Force deduction programming problem - solution summary
力扣解法汇总面试题 17.11-单词距离
The program actively carries out telephone short message alarm, and customizes telephone, short message and nail alarm notifications
Common errors when mysql8 connects through JDBC
Maya Front Office Rendering plug - in Mel script Tool
力扣解法汇总1728-猫和老鼠 II