C++ template type inference is divided into class template type inference and function template type inference. The main discussion here is C++ function template inference.
There are three types of function template type inference situations:
Situation 1:
template<typename T>
void func(T t)
{
//....
}
This situation is the simplest. For the actual parameter val passed to the function template, suppose its type is ParaType. If ParaType has a reference attribute, then remove the reference attribute. If it has a const attribute, remove the reference attribute. The final type is the type of T:
int i = 999;
func(i); //实参i既无引用属性,也无const属性,T类型为int
const int ci = 250;
func(ci); //实参ci有const属性,去掉,T类型为int
const int &cref = 520;
func(cref); //去掉实参cref引用属性和const属性,T类型为int
Situation 2:
template<typename T>
void func(T &t)
{
//...
}
In this case, for the actual parameter val passed to the function template, the type is ParaType. If ParaType has a reference attribute, the reference attribute is removed, and if it has a const attribute, it is retained.
int i = 999;
func(i); //实参i既无引用属性,也无const属性,T类型为int
const int ci = 250;
func(ci); //实参ci有const属性,T类型为const int
const int &cref = 520;
func(cref); //去掉实参cref引用属性,T类型为const int
const int &&crref = 6666;
func(crref); //去掉实参crref引用属性,T类型为const int
Situation 3:
template<typename T>
void func(T &&t)
{
//...
}
This situation is the so-called universal reference. The actual parameter type can be any type (lvalue, rvalue, lvalue reference, rvalue reference, although the template function const T&
can be declared to receive any type, but the actual parameter cannot be modified. limits).
For the actual parameters passed to this function template:
- When the argument type is lvalue** (note that lvalue, lvalue reference, and rvalue reference are all lvalues) **, the type of T will be inferred
type&
; when the type of the argument is an rvalue, the type of T Would be inferred to betype
. Thattype
what type is it?type
That is, the derivation rule in the second case above.
For example:
std::string s("fuck");
func(s); //s为左值,type为std::stirng , T被推断为std::string &
const std::string &lref = s;
func(lref); //lref为左值,type为const std::string T被推导为const std::string &
const std::string &&rref = std::string("fuck c++");
func(rref); //同上
- When the actual parameter type is an rvalue, the type of T is inferred to be the corresponding type of the actual parameter.
For example:
func(std::string("hello c++"); //T被推断为std::string
std::string s("give up c++");
func(std::move(s)); //T被推断为std::string
func(static_cast<std::string &&>(s)); //T被推断为 std::string
So far, all the types of T are known. You can directly bring the inferred type into the function template to get the instantiated function, for example:
//情况一
func(int t) //T为int
{
//...
}
//情况二
func(const int &t) //T为const int
{
//...
}
//情况三,实参为左值时
func(const std::string& &&t) //T为const std::string &
{
//...
}
//情况三,实参为右值时
func(std::string &&t) /T为std::string
{
//...
}
In case three, the instantiation result is a bit strange when the actual parameter is an lvalue. The compiler does not allow the programmer to write this directly, folding by reference, the final version is:
//可以看到,当实参为左值类型(左值、左值引用、右值引用)时,最终t都会绑定到一个左值对象或右值对象上
func(const std::string &t)
{
//....
}