原文档地址:https://www.yuque.com/yuqueyonghubpajeq/wdr7hn/dtockwla49ulgqhh
Flow control:Conditional programming
do different things based on the conditions that we have set up in our code
ex:
keyword:
If statement
if(a bool){
}
else{
}
else statement
if(a bool){
}
else{
}
nested conditions 嵌套条件
nested alternative
using logical operators
and &&
or ||
not !
else if statement
if(a bool){
}
else if(a bool){
}
……
switch statement
switch(condition){
case condition 1 :{
}
break; ------if condition = condition 1, execute case and break switch
else,judge next case
case condition 2 :{
}
break;
……
default:{
}
break; --------if all cases don't satisfy,then execute default and break switch
no else
}
Ternary Operator
1.result =( a bool ) ? option1:option2;
result is the same variable/data type as option1/option2
2.result =( a bool ) ? option1:option2; --- is equivalent to below
3.a new initializtion:
ex1:
a compiler error
a,b should be convertible
ex2:
22.5f is turned into a integer
auto make sense
ex3:
Loop
For loop
format 1:
for(statring point of iterator; test(a bool) ; increment) {
}
ex:
execute at i=0~9
format 2:
int a[10]{0,1,2,3,4,5,6,7,8,9}
for(size_t i : a){
}
注:.use character array to do for loop
anther iterator --- size_t:
it occupy 8 bytes ----have a good range of value
can only represent positive number
alias(别名)
ex:
iterator can be scope inside the body of for loop
iterator can be initialized outside the loop
and neglect iterator declaration in the loop
changeable test
Attention
for (int j = 0; j < nums.size(); ++j)
for (int j = 0; j < nums.size(); j++)
两种写法在大多数情况下是等价的,但在某些场景下可能会有微小的性能差异,这取决于编译器的实现方式。
等价于
for (int j = 0; j <= nums.size()-1; ++j)
for (int j = 0; j <= nums.size()-1; j++)
等价于:
while (j < nums.size()) { // 循环条件
statement;
i++; // 递增循环变量
}
while (j < nums.size()) { // 循环条件
statement;
++i; // 递增循环变量
}
注:1.
i++是后缀递增运算符,它先返回i的当前值,然后再将i的值增加1。
++i是前缀递增运算符,它先将i的值增加1,然后再返回i的新值。
-
- i++返回i的旧值,然后将i增加1。
- ++i返回i的新值(增加1之后的值)
对单独成行的 i++ 和 i--来说没有区别
2.对num[i++]; ---num[i]; i++;/++i;
对num[++i]; --- i++;/++i; num[i];
While loop
format:
iterator initiliztion
while( test(a bool) ){
increment;
}
iterator is declare outside
increment is inside
注:use pointer of a character array to do while loop
ex:
Do while loop
format:
iterator initiliztion
do{
increment;
}while( test(a bool) );
the test is after increment
use pointer as a bool in loop
任何非零的指针值,被视为真(true)
零值指针(NULL)被视为假(false)。
//name is point (to char)
if (name)
uart_printf("Board: %s", name);
Arrays
group all variables into one single unity or collection
manipulate them as a single unit
Array is a kind of data structure.
if a array call scores
indexs to refer to certain variable
indexs begin at 0 not 1
declare and use an arrays
declare an array:
data_type array_name[ quantities of data] ;
use(read) an array:
array_name[ certain index]
(1)once an array is declare
there is no data we have put in
(2)arrays are indexed from 0 not 1
reading out array bound may read garbage data
ex:
write data into array
write data into array singly
array_name[index 1] = value 1;
array_name[index 2] = value 2;
……
ex1:
ex2:
write data with a loop
read data with a loop
declare and write data into array at same time
format:
variable_type array_name[ number of variables] {value1,value2,value3,……};
(1)is value number less than number of variables,those leaving out are initilize to 0
(2)neglect the number of variables
the compiler will dedeuce the number for the
number of value
(3)once a element of aryay is declare and write
as a constant value,it can't be modified
(4)use array to do math operation
int element : scores 是C++中的一种范围-based for 循环语法,也被称为 "range-based for loop"。它的作用是遍历一个容器(例如数组或容器类),将容器中的每个元素依次赋值给循环中的变量(在这里是element),然后执行循环体中的操作。
在你的代码中,scores 是一个整数数组,int element 声明了一个整数类型的变量 element,而 : scores 表示从数组 scores 中取出每个元素,并将其依次赋值给 element,然后执行循环体内的代码块。
具体来说,这个循环将遍历数组 scores 中的每个元素,将每个元素的值加到 sum 变量中,从而实现了对数组中所有元素求和的操作。这是一种更简洁的方式来遍历数组,特别是当你不需要索引时。
ex:
Pointer
a special type of variable to store addresses to other variables
declare and use pointers
declare a pointer:
format1:
variable_type * pointer_name ;
it will randomly assign a memory to pointer to point
format2:
variable_type * pointer_name {};
equal to
variable_type * pointer_name{nullptr};
(1)once declaration done,that poiner can only store an address of a variable of variable_type
(2)size of pointers are same (8 bytes),no matter what variable types' address they store
(3)make sure pointer is declared and initialized ,even initialized with nullptr
(2)position of * doesn't matter
(3)confuse case
declare and initialize a pointer to nullptr:
format 1
variable_type * p_number {nullptr};
(1)can only store an address of a variable of variable_type
(2)address of nullptr means the pointers are not pointed in anywhere.
format 2:
variable_type * p_number {another pointer of the same variable_type};
or
variable_type * p_number {number of address};
or
variable_type * p_number=&another pointer of the same variable_type;
or
variable_type * p_number= number of address;
format 3:
variable_type * p_number {nullptr};
(or variable_type * p_number {}; or variable_type * p_number; )
* p_number = a number of address;
(or p_number =&another variable of the same variable_type;)
use a pointer
*pointer_name --- print out the value of the memory address that the pointer point to
pointer_name --- print out the address the pointer store
- "p_number points to a VALID address : " << p_number << std::endl;这行代码打印的是指针 p_number 的值,也就是它所指向的地址。它会输出指针的十六进制地址,例如 0x7ffd5914f9d4。这是在告诉你指针 p_number 存储的内存地址是有效的,但它没有解引用指针来获取存储在该地址上的值。
- "p_number points to a VALID address : " << *p_number << std::endl;这行代码打印的是指针 p_number 所指向地址上存储的值,通过解引用指针 *p_number 来获取。如果 p_number 指向有效的内存位置,那么这行代码将打印该地址上的值。如果 p_number 不是一个有效指针(例如,它是空指针),这可能导致未定义行为或程序崩溃。
write data into pointer
if there exist a variable called variable 1
the address of variable1 can be represent as &variable1
we can assign this value to a pointer
format 1:
variabe1_type * pointer_name{&variable1}
format 2:
variabe1_type * pointer_name{the number of address}
modify the pointer value after initialization
format 1:
pointer_name=&variable2;
format 2:
pointer_name=the number of address;
type of variable2 must corrospond to variable1
pointer to char
???????????
declare a pointer to a char
for pointer to one character :
format:
for pointer to string:
format:
char * pointer_name { the string };
message2 is declared as a pointer to a character (string)
*message2---- the first character of the string, which is 'H'.
print message2------ the memory address where the string "Hello there" is stored.
for pointer to characters array:
format:
char * pointer_name[] {the character array} ;
message2 is declared as an array of pointers to characters (strings) ,even it is initialize with a string -: "Hello there"
dereference *message2,-----the first character of the first string in the array, which is 'H'.
print message2---- the memory address of the array of pointers
modify a pointer
注:
if initialize with string literal
but the compiler specify string as an array of charaters
so *p_message is an char array pointer
it can only be modified to another address of char array
next will get a compiler error
print out pointer to char
print pointer to one character :
print out pointer to a string
print out pointer to a character array
use pointer as a bool in loop
在C++中,指针可以用作条件表达式,而不必显式解引用指针。
当您使用if (output)时,它会检查指针output是否为非空(即指向有效的内存地址),
如果是非空的,则条件为真,进入if语句。
这是C++的惯用做法,而不需要显式解引用指针。
program memory map
program.cpp→compiler→ binary executable.exe
binary executable(application) can run on an operating system
binary executable(application) will load in computer memory(ram)→a special section of ram called program area
Dynamic memory allocation
use that technique to start using heap storage in memory map
use dynamic memeory allocation to get additional memory
use it to do stuff if stack memory isn't enough
use memory allocated on the stack
initilize a pointer without a certain address may lead to crash
initilize a pointer with nullptr may lead to crash
use memory allocated on the heap
stack
developer isn't in full of control when variable die
-----mean once a variable is declared and initialize on the stack,the memory that the variable occupy can't be controled once it is wiped out of memory
only when scope (in which it was declared) is run out,the variable can be killed
so in the stack we can't control when the varible die
because it depend on scope mechanism(only when scope is run out)
wipe out != kill
heap
heap is a addtional memory that you can use but don't worry it will run out
developer isn't in full of control when the variable comes to life and die
lifetime through scope mechanism
local_scoupe_var is limited to the curly brace
is come to life when statement is executed
is going to die when } is execute
{ } -----scope
out of the scope the varibles inside it will die --mechannism
dynamic memory using "new" operator
allocation dynamic memory on heap using "new"
format 1:
variable_type * pointer_name{nullptr};
pointer_name = new variable_type;
*pointer_name = a number of address; (or pointer_name=&another variable of same variable_type )
format 2:
variable_type * pointer_name{new variable_type(a number of address)};
or
variable_type * pointer_name{new variable_type {a number of address} };
- int* lots_of_ints1 { new int[1008808000080000000] }; 这句代码创建了一个指向整数的指针 lots_of_ints1,并尝试在堆上分配一个非常大的整数数组,数组的大小为 1008808000080000000。这个尝试分配如此大的数组可能会导致内存不足或其他问题,并且通常不是合理的做法。
- int* lots_of_ints1 { new int{1008808000080000000} }; 这句代码创建了一个指向整数的指针 lots_of_ints1,并在堆上分配一个整数,该整数的值为 1008808000080000000。这个操作通常是合法的,但要注意整数是否能容纳这么大的值,否则可能会导致溢出。
- int* lots_of_ints1 { new int(1008808000080000000) }; 这句代码与第二句类似,也是创建了一个指向整数的指针 lots_of_ints1,并在堆上分配一个整数,该整数的值为 1008808000080000000。这是使用括号初始化整数的另一种方式,与第二句的效果相同
format 3:
variable_type * pointer_name=new variable_type;
*pointer_name = a number of address;(or pointer_name=&another variable of same variable_type )
注:
1.pointer_name=&another variable of same variable_type
*pointer_name= a number of address;
2.the expression of “new variable_type”
(1)new is used to let operating system alloate memory on the heap not the stack
(2)large enough to accomendate a integer(4 bytes)
(3)this program can use that piece of memory ,other program on the system can't until i return it to the system
ex:
release and reset
release(delete) the memory that a pointer point and reset the pointer to nullptr
if no reset the pointer ,beacuse there is no memory that the pointer point ,once use the pointer ,it will lead to crash
return memory that this pointer occupy to the system
can't delete twice
Dangling pointers
three kind of dangling pointers
declare but uninitialized pointer
don't know which address is stored in the point
put something there may lead to a crash
deleted pointer
release(delete) the memory that a pointer point but not reset the pointer to nullptr
beacuse there is no memory that the pointer point ,once use the pointer ,it will lead to crash
pointers pointing to same address
pointers pointing to same address will not lead to crash
but once the memory that a pointer point is deleted
the memory that the rest pointers points is deleted
once use one of these all pointers,it will lead to a crash
solutions
1.make sure a declared poiner is initialized,even with nullptr
2.reset pointer to nullptr after the memory that it points is deleted
When "new" operator fails
'new' operator is used to allocate dynamic memory on the heap
1.int* lots_of_ints1 { new int[1008808000080000000] }; 这句代码创建了一个指向整数的指针 lots_of_ints1,并尝试在堆上分配一个非常大的整数数组,数组的大小为 1008808000080000000。这个尝试分配如此大的数组可能会导致内存不足或其他问题,并且通常不是合理的做法
2.多次 少量动态分配 多个数组 也 可能会导致内存不足
ways to handle the problem
std::exception mechanism
#include <iostream>
#include <stdexcept>
int main() {
try {
throw std::runtime_error("This is a custom exception.");
} catch (const std::exception& e) {
std::cout << "Caught an exception: " << e.what() << std::endl;
}
return 0;
}
std::exception 包含了一个用于提供异常描述信息的虚拟成员函数 what(),它返回一个 C 风格的字符串(const char*),用于描述异常的信息。这个信息通常是一个人可读的文本,用于解释为什么发生了异常。
当在 C++ 中使用异常处理机制时,你可以捕获不同类型的异常,包括派生自 std::exception 的异常类,以及自定义的异常类。通过捕获和处理异常,你可以更好地管理程序中的错误和异常情况。
在上面的示例中,我们抛出了一个派生自 std::exception 的异常类 std::runtime_error,然后在 catch 块中捕获并使用 what() 函数获取异常的描述信息。这有助于提供有关异常的更多信息,以便进行适当的错误处理
ex is a variable used to catch what kind of problem happen in try
std::nothrow
std::nothrow 是 C++ 标准库中的一个对象,通常用于在动态内存分配时,告诉分配函数不要抛出异常。在标准 C++ 中,当使用 new 运算符分配内存时,如果分配失败,会抛出 std::bad_alloc 异常。但是,如果你使用了 std::nothrow,那么在分配失败时,它不会抛出异常,而是返回一个空指针或者一个表示分配失败的特殊值,具体取决于分配函数的实现。
使用 std::nothrow 的主要优势在于,它可以让你更好地控制和处理内存分配失败的情况,而不必处理异常。这在一些低级的系统编程或者对异常处理有特殊要求的情况下非常有用。
tell the sysytem not to throw a exception when "new" operator fail
Null pointer safely
pointer can impliccitly converted into a boolean exp
we can deleter nullptr same as other pointers ,don't need to check
it will cause no problem
Memory leak
ex1:
ex2:
ex3:
out of scope ,p_number 2 can't be accessed to delete
so delete it in the scope
Dynamic arrays
declare a dynamic array and its pointer
format 1:
format 2:
use dynamic array and its pointer
relase the memory of dynamic array 's pointer
dynamic array different from array
error:dynamic array doesn 't have array properties that are needed for the range based for loop to work.
Reference
a way to set up alias for variable
go through the reference(alias variable ) and use it in pretty much the same way we use variable
declare reference
format1:
datatype& reference_name{varible_name of the same type}
format2:
datatype& reference_name=varible_name of the same type
注:& can be used in other place
& a varibale ---the address of that variable
use reference
use reference_name as same as original variable
&reference_name-----the address of original variable
modify data through reference
modify value of original varible through its reference
Comparison between pointer and reference
similarity:
pointer: store the address of a variable
go through that pointer and modify the original variable
difference:
1.reference need to be initialize with a variable
pointer can choose not to initilize but contain a junk address
2.reference: reference directly
don't use dereference(间接引用 *) to get the value of original variable
pointer: use dereference(*) operater to get the value of original variable
3.reference: only reference specific varibale
if change the reference,the value of original variable will change
pointer:change another variable to reference
reference are somewhat like const pointer
Reference and const reference
const reference
constant key word can be used with reference
1.set up a reference(alias) to a variable
2.initialize it with const
the reference will lose the property that modify the value of original variable through that reference
format:
const variable_type & const_refernence_name
ex:with no const reference
ex:with const reference
const pointer
format:
const variable_name * const const_pointer_name(& a const)
the pointer will lose the property that modify the value of original variable through dereference(*)
Character and String Manipulation
c
model a character array and store a bunch of characters
---character array
can manipulate it in memory
this is the way text data is stored in c++
a lot of facilities(character array facilities) built on top of this character(character array construct) to easily work with text data
use character array to model c string which are facilities we used in c to handle text data
C-String:
built-in facilities used to manipulate text data
c-string are not safe and convenient to work with
std::string
another type that built on the top of character arrays
it is a easy interface to work with
just focus on storing any data and doing stuff with it in our c
character manipulation
some facilities in c standard library that helo manipulate characters
cctype library:
https://en.cppreference.com/w/cpp/header/cctype
ex1:
Non-zero value if the character is an alphanumeric character, 0 otherwise.
ex2:
ex:
ex3:
ex4:
C-String manipulation
c-string library:
https://en.cppreference.com/w/cpp/header/cstring
how to manipulate c string----contatenate ,put together ,copy,,,,
std::strlen
length of a string (ignore null character of the string)
sizeof operater :
also can calculater the length of a string (include null character of the string)
ex:
std::strcmp
compare strings in lexicograpgical(词典学) order
format:
std::strcmp(string1,string2)
negative value if string1 appears before string2 in lexicographical order.
zero if compare equal.
positive value if string1 appears after string2 in lexicographical order.
ex:
ex:
- const char * string data1 { "Alabama" };这行代码定义了一个指向字符常量的指针 data1,并将它初始化为指向字符串字面值 "Alabama" 的首字符的地址。换句话说,data1 是一个指向字符串的指针,而该字符串是不可修改的,因为它是一个字符常量。
- const char * string data1 []{ "Alabama" };这行代码定义了一个字符指针数组 data1,并将其初始化为包含一个元素的数组,该元素是指向字符串字面值 "Alabama" 的首字符的地址的指针。这表示 data1 是一个指针数组,其中的元素都是字符指针。
- 第一行代码定义了一个单一的字符指针,它指向一个字符串字面值。
- 第二行代码定义了一个包含一个字符指针的指针数组,该字符指针指向一个字符串字面值。
根据需求,可以选择使用其中一个即可
std::strchr
find out the first occurrence of target character in a string
format:
std::strchr(string,target character)
std::strchr函数的返回值是一个指针
指向字符数组 str 中第一次出现字符 character 的位置的指针,如果未找到字符,则返回空指针(nullptr)
std::strrchr
find out the last occurrence of target character in a string
ex:
ouput is a pointer
C-string concatenation and Copying
std::strcat
allow to join strings
format
string1=std::strcat(string1,string2)
ex1:
ex2:
std::strncat
format
string1 =std::strncat(string1,string2,the number of character copied from string2)
std::strcpy
format:
char_pointer1=std::strcpy(char_pointer1,char_pointer1)
copy from char_pointer2
paste in char_pointer1
std::strncpy
char_pointer1=std::strcpy(char_pointer1,char_pointer1,the number of character copied from char_pointer1)
Introduction std::string
a variable(data) type make it easy to work with string data
and don't need to worry unly little details( array bounds,the null character,etc)
string library
declare std::string variable
modify std::string
One definition rule
tune to:
ex for variaable:
exception for class:
First Hand on C++ Functions
define a function
function with input and output:
ex:
function without input or output:
viod ------this functin is not going to return anything
empty () -- no input
ex:
ex:
ex:
function is unique because of its signature:
function signature include function name and function parameters
use a function
use a function with input and output:
use a function without input and output:
ex:
argument scope
自变量范围
operations of inputs in the argument scope will not change the value of inputs outside the argument scope
compiler will make copy of h and i
and assign them to a and b
Function Declaration and Function Definitions
used to define a function first(even it is out of int main ) and then use
in this part
seperate function in to two part
1.Declaration(prototype)----declare a function before use it (even ahead of int main )
2.use that function bewteen declaration and definition
3.Definition----------------define a function after use it (even after the } of int main)
ex1:
ex2:
Function across Multiple Files:Compilation Model Revisited
ex;
ex:
definition of function can live any where in code
the linker is smart enough to parse entire project(include multiple files) looking for the definition of function
it keep looking until it finish looking in all translataion units
when it can find the definition of function but you use it,it will give a linker error
ex:
one file
ex:
function across multiple files
if compare.cpp is deleted
ld is a linker error of gcc
is a linker error of msvc
Pass parameter through function
pass by value
Pass parameters through function by value(mechanism)
---------if pass a variable to a functin,it is going to pass a copy of actul variable
insider the body of funtion,it just work with the copy of actul variable
the copy of actul variable disappear out of scope of function
ex:
although the varible_name is same as para_name
parameter only receive the copy of original variable
pass by pointer
Pass parameters through function by pointer
---------if pass a variable to a functin,it is going to pass a copy of actul pointer
insider the body of funtion,it just work with the copy of actul pointer
the copy of actul pointer disappear out of scope of function
1.operation to dereference of pointer inside function will change the value that the copied pointer point to(if no operation to the copied pointer inside function ,the copied poinet =original pointer)
so if no operation to the copied pointer inside function,operation to dereference of pointer inside function will change the value that the orginal pointer point to
(because the machanism of pointer)
2.if operation to the copied pointer inside function ,it will not change orginal pointer
ex:
although the pointer_name is same as para_name
parameter only receive the copy pointer of original variable
use the copy pointer of original variable to dereference(*) the value of original variable inside function
pass by reference
Pass parameters through function by reference
----------------the operation to the alias of variable inside function wil change the variable
the change we do to reference in function are going to be visible when function retun
ex:
the alias of variable is passed to parameter
the operation to the alias of variable inside function wil change the variable
because of the property of reference
the change we do to reference in function are going to be visible when function retun
Get things(data) out of function
two ways to get things out of function
returning from function by value
use return in the function to pass output to the outside of function
format:
1.output variable should be initialize in the function
2.return output_variable;-----at the bottom of function
3.funtion_name(parameters) -------is the value of output variable
In detail:
it will copy whatever of output variable the function return and store a copy of it
in funtion_name(parameters)
but don't rely to this
we should set output_variable same inside and outside varible to let compiler optimize to jump the process of copy when the output contain moutainless data
like:
return output_variable; -----at the bottlom of function
output_variable=funtion_name(parameters) -------is the value of output variable
ex:
two result is different in sum function and main function
ex:
the address of output inside and outside funtion is same
it is beacuse the compiler don't execute the copy opertaion
it just reuse the address of output inside funtion and copy it to the address of output outside funtion(return by pointer)
it is a optimization
input and output parameter
parameter is something to be passed into function
it is not only input but also can be output
use function parameter as channials to get thing out of function
注:output parameter should be initialize out of { } of the function
input parameter syntax of void:
varible:
std::vector --- dynamic array
std::string/std::vecotr can be regarded as a variable type
pointer:
reference:
output parameter syntax of void:
reference :
why?
the change we do to reference in function are going to be visible when function return
注: void funtion can't output anything
the output of void function is actually in ( ) of void function in input format
pointer:
1.operation to dereference of pointer inside function will change the value that the copied pointer point to(if no operation to the copied pointer inside function ,the copied poinet =original pointer)
so if no operation to the copied pointer inside function,operation to dereference of pointer inside function will change the value that the orginal pointer point to
2.if operation to the copied pointer inside function ,it will not change orginal pointer
ex:reference output
ex: pointer output
Function overloading
function overloading is a mechanism to have mutiple functions of same name in c
but taking different parameters
how to set up function overload based on different function parameters
overloading with different parameters
can overload the functions of same name
if the order or number or type of parameter is differert
ex:
Lambda function
get them to do things directly
declare lambda function
format1:
[ ]( )->return data_type{
};
format2:
auto variable_name [ ]( )->return data_type{
};
[ ]----- a capture list
( )------parameters to put in
>return data_type---------this lambda function is going to be forced to return that data_type (implicitly converted data_type )
even you pass it to parameters that are not data_type
ex:
if dont give the function a name and assign the entire lambda function a variable and use it
the lambda function will not be called (excuete)
give the function a name and assign the entire lambda function a variable
the variable is a handle and use it to do things with lambda function
use lamda fuction
format:
var_of_lambdafunction(the value of parameters );
ex:
give the function a name and assign the entire lambda function a variable
the variable is a handle and use it to do things with lambda function
directly declare and use lambda function
format1:
[ ]( parameters){
}( the value of parameters );
format2:
auto variable_name=[ ]( parameters)->return data_type{
}( the value of parameters );
three equality:
1.[ ]( parameters)->return data_type{
}( the value of parameters );
2.variable_name;
3.var_of_lambdafunction(the value of parameters );var_of_lambdafunction(the value of parameters );
ex:
lambda function is called (executed),but do nonthing on the console
capture list:
use things (that is declared and initilized out of the scope of lambda function ) inside the lambda function
but these thing are not the parameters in ( )
capeture by value:
capture by reference:
capture all in text
[=]----------------------------------------------capture everything by value
[&]----------------------------------------------capture everything by reference
Function template
or template function
a mechanism to set up blueprint/template for function
have one point control to set up function
compiler will generate the actual function that get called
function template are an effort to solve problem like overload of function
set up a bluepoint/template for function
the compiler will use this blueprint/template to generate an actual function when call(use) this function
try out function template
declare funtion with blueprint:
syntax:
tempate <type_name T>
T function_name(T a,T b);
注:The overall syntax is a blueprint
- template: 这个关键字表明接下来的代码是一个模板声明,它告诉编译器后面定义的类或函数是一个模板。
- <typename T>: 这是模板参数列表,用尖括号 <> 括起来,里面是模板参数的声明。在这个例子中,typename T 表示声明了一个模板参数 T,typename 是告诉编译器 T 是一个类型参数的关键字。你也可以使用 class 关键字替代 typename,效果是相同的。
- T: 这是模板参数的名称。它是一个占位符,表示在模板被实例化时将要替换为实际的类型。你可以使用任何有效的标识符作为模板参数的名称。
因此,template<typename T> 这行代码告诉编译器,接下来定义的类或函数是一个模板,它有一个类型参数 T。在模板被实例化时,T 将会被替换为调用时传入的具体类型。
实例化:根据实际的参数类型生成相应的函数实例
define function with blue point:
syntax:
tempate <type_name T>
T function_name(T a,T b){
}
equla to:
auto function_name(auto a,auto b){
}
ex:
use/call funtion template
function_name<output type>( parameters)
注:<output type>----force the output to be that type if it can be reasonable
注:
1.The compiler will use this blueprint to generate an actual function
based on what variable_type is called(used) in this function
In detail ,if firstly got int input,it will generate int version function (that is called int template instance)
it will resued it when for double typeinput ...etc
2.function template are just blueprint., they are not real function declaration and definition
3.when call/use the function,the compiler will generate a real function declaration and definition(also
known as template instance )
4. The real function declaration and definition(also known as template instance ) will be reused when a similar function
5. If use funtion template ,it mean all inputs and output must be same type
or compile error(except some reasonable cases)
aka---also known as
ex:
function overload
use function template
insight of function template
Template type deduction and Explicit arguments/parameter
Template type deduction
When call the function template, the template instance will be set up based on the type of input para/argument.
----------template parameter (it is what you have in your template function declaration or defination)
---------template argument/parameter (it is what you call/use template )
Explicit arguments/parameter
when call/use the function
sytax:
function_name<varibale_type>(paras)
- 模板类型推导(Template Type Deduction):
-
- 模板类型推导是指编译器根据函数调用或对象创建的上下文,推断模板参数的具体类型。
- 当我们调用模板函数或创建模板类的对象时,可以省略模板参数的类型,而让编译器根据传递给模板的参数来推断类型。
- 例如:
cppCopy code
template<typename T>
void foo(T a) {
// 函数体
}
int main() {
foo(5); // 在这里,编译器会推断 T 的类型为 int
foo("hello"); // 在这里,编译器会推断 T 的类型为 const char*
return 0;
}
- 显式参数(Explicit Arguments):
-
- 显式参数是指在调用模板函数或创建模板类对象时,显式指定模板参数的类型。
- 即使编译器能够推断出模板参数的类型,我们也可以显式地指定类型。
- 例如:
cppCopy code
template<typename T>
void foo(T a) {
// 函数体
}
int main() {
foo<int>(5); // 在这里,显式指定了 T 的类型为 int
foo<const char*>("hello"); // 在这里,显式指定了 T 的类型为 const char*
return 0;
}
模板类型推导允许编译器根据上下文推断模板参数的类型,而显式参数允许我们明确地指定模板参数的类型,即使编译器也能够推断出类型
Template parameters by reference
syntax:
template <type name T>
const T& maximum(const T& a,cont T& b);
ex:
confue compiler and lead to a compiler error
the solution:
substitute
maximum(a, b)
with
maximum<double>(a, b) using explicit argument/parameter
Template Specialization
declare a template specialization:
template<>
variable_type function_name<output type>(variable_type parameters)
define a template specialization:
template<>
variable_type function_name<output type>(variable_type parameters){
};
1.it is like funtion but not funtion,
it is a appendix to a funtion
2.template specializtion is a feature to bypass the default mechanism of how templates work
3.template specializtion is a mechanism to tell the compiler for a template function:if pass compiler this type template funtion(this type template instance),don't do the default of replacing the argument type for the template parameters.instead use the implement that give in template specialization.
Class Template
or template class
为什么需要模板类? 和模板函数(Function template)基本相似
是为了对 模板/函数 更通用,适用于不同的数据类型
format:
cppCopy code
template<typename T>
class MyContainer {
private:
T data;
public:
// 构造函数
MyContainer(const T& value) : data(value) {}
// 获取数据
T get_data() const {
return data;
}
// 设置数据
void set_data(const T& value) {
data = value;
}
};
在使用过程中,模板类通过实例化(instance,这个词在function template中有提到)就
模板对象(Template Object)是通过实例化类模板(Template Class)创建的对象
Intro to C++20 Concepts
concept is a mechanism to used to set up constraints or restrictions on template parameters in our function template
ex:can use concepts to make our template function to be only called with integers
and if call that template function that isn't int ,it will give a complie error
two sides to concepts in c
#include<concepts>
use to enforce ur template function to be only called in some particularle constraint
concepts in standard library
use concept when defining function
syntax1:
template <typename T>
requires std::integral<T>
T add (T a, T b){
return a + b;
}
syntax2:
template <std::integral T>
T add (T a, T b){
return a + b;
}
syntax3:
auto add (std::integral auto a,std::integral auto b)
return a + b;
syntax4:
template <typename T>
T add (T a, T b) requires std::integral<T>{
return a +b;
}
syntax5:using type traint
template <typename T>
requires std::is_integral_v<T>
T add (T a,T b){
return a + b;
}
C++ 中的 type traits(类型特征)是一种编程技术,它允许您在编译时查询和操作类型信息,而不是在运行时。这对于泛型编程和模板元编程非常有用,因为它可以帮助您根据类型的特性来执行不同的操作或生成不同的代码。
C++ 标准库提供了一组类型特征的模板类和函数,这些类型特征允许您检查类型的属性,例如:
- 是否是整数类型
- 是否是浮点数类型
- 是否是数组类型
- 是否是类类型
- 是否是指针类型
- 是否可以执行某个操作(例如,是否可以进行复制构造)
一些常用的 type traits 类包括 <type_traits> 头文件中的 std::is_integral、std::is_floating_point、std::is_array、std::is_class、std::is_pointer 等等。
以下是一个简单的示例,演示如何使用类型特征检查一个类型是否是整数类型:
build own concept(custom concepts)
set up own concept
(1)use type trait:
syntax:
template<typename T>
concept concept_name = std::type_trait_v<T>;
"_v" 的作用是获取类型特征的值(value),它返回一个 bool 类型的常量表达式,表示所查询的类型特征是否为真或假
(2)use require clause
syntax:
template<typename T>
concept concept_name = require (T a, T b){
require clauses;
}
require ( T a,T b) means a,b must be the type of template T(T has be constrain by concept before)or it will compile error
ex:
std::is_integral 是一个 C++ 标准库中的类型特征,用于判断一个类型是否是整数类型。
use own concept (custom concepts) in defining function
syntax1:
template <typename T>
requires concept_name<T>
T function_name(T a,T b){
detail of function;
}
syntax2:
template <concept_name T>
T function_nameT a ,T b) requires concept_name<T>{
detail of function;
}
syntax3:
auto function_name(concept_name auto a, concept_name auto b){
detail of function;
}
require clause:
in setting up own concept
only check but if it don't satisfied ,no bool is produced
noexcept: noexcept 是一个异常规范说明符,它表示在执行 {a + b} 表达式时,不会抛出异常。这意味着 a + b 必须是一个不会引发异常的操作
-> 在这里用于指定 std::convertible_to<int> 作为 {a + b} 表达式的期望返回类型。
std::convertible_to<int>: 这部分表示 {a + b} 的结果必须是可以隐式转换为 int 类型的。这意味着 {a + b} 的结果必须是一个可以被转换为 int 的类型
Logical combinations of concept
it is conbined when using the concept
case1:
conbine two own concepts when using the concept
format1:
if two own concepts have set up
template<typename T>
T function_name concept_name1<T> logical_operator concept_name2<T> {
detail of function;
}
format2:
template<typename T>
T function_name requires(T a, T b){
require clauses;
} logical_operator requires (T a, T b){
require clauses;
}{
detail of function
}
case2:
combine two standard concept
template<typename T>
T function_name requires std::concept1<T> logical_operator requires std::concept2<T> {
detail of function;
}
ex:
concepts and auto
used when defining function
format1:
for standard concept
std::concept auto function_name(std::concept auto parameters){
detail of function;
}
format2:
concept _name auto function_name(concept _name auto parameters){
detail of function;
}
used when declare variable
useless