c++ 模板实参推断

于函数模板,编译器用实参来推断模板参数

这个过程成为模板实参推断

类型转换与模板类型参数

一般而言,不会转化实参以匹配已有的实例化,相反,会产生新的实例化,或产生不了实例化,报错。

只有两个例外:

  • const转换:

    • 如果模板形参为const引用,则其可以接受const或非const引用
    • 如果模板形参为const指针,则其可以接受const或非const指针
    • 如果模板形参不是引用或指针 (值传递),则形参和实参都忽略const
  • 数组或函数到指针的转换

    • 如果模板形参不是引用或指针(值传递),则数组会转化为指针,数组实参将当作指向其第一个元素的指针;
    • 如果模板形参不是引用或指针(值传递),则函数会转化为指针,函数实参将当作指向函数类型的指针;
1
2
3
4
5
6
7
8
9
10
11
12
template <typename T> T fobj(T, T);//值传递  
template <typename T> T fref(const T&, const T&);//引用

string s1("a value");
const string s2("another value");

fobj(s1,s2);//值传递,const被忽略
fref(s1,s2);//引用,s1也被转成了const引用

int a[10], b[42];
fobj(a, b);//值传递,数组被转成指针,T被推断为int *,f(int*,int*)
fref(a, b);//Error!!,引用,a导致T被推断为int(&T)[5]、b导致T被推断为int(&T)[5],矛盾

函数模板显式实参

定义一个模板

1
2
template<typename T1, typename T2>
T1 sum(T1 s);

从这个函数实参我们仅仅可以推断出T2的类型

因此,为了推断出T1,必须为显式指定这两个类型

1
auto val2=sum<int, long>(i);

尾指返回类型与类型转换

当你遇到这种情况

1
2
3
4
template<typename T>
??? &fcn(T beg, T end) {
return *beg;
}

这时,你无法确定返回值是什么,

你知道的只有接收一对迭代器和要返回一个元素的引用

这时你就需要decltype

1
2
3
4
template<typename T>
auto fcn(T beg, T end)->decltype(*beg) {
return *beg;
}

要是你想返回的不是引用而是一个值

那么,你需要remove_reference::type

1
2
3
4
5
template<typename T>
auto fcn(T beg, T end)->
typename remove_reference<decltype(*beg)>::type {
return *beg;
}

根据指针类型来推断模板实参

1
2
3
template <typename T>
T compare(const T&, const T&);
int (*f)(const int&, const int&) = compare;

此时,T=int;

1
2
3
4
5
template <typename T>
T compare(const T&, const T&);
void func(int(*)(const int&, const int&));
void func(string(*)(const string&, const string&));
func(compare);//error

因为无法判断使用compare的哪一个版本
想要成功调用,只能显式声明

1
func(compare<int>);