创建通用引用的重载函数,但很多时候还是会调用到通用引用函数,这会让人很迷惑。
普通版本
假设我们要实现一个函数,用于存入传递进来的std::string
,普通版本如下:
1 | std::multiset<std::string> names; // global data structure |
在使用的时候如下:
1 | std::string petName("Darla"); |
第一种情况传入的是左值,且形参name
也是左值,它以拷贝的方式加入全局变量names
。
第二种情况创建了临时对象传递给name
,形参name
是左值,它以拷贝的方式加入全局变量names
。但这种情况下,我们实际上是可以以移动的方式加入names
的。
第三种情况隐式通过字面值字符串创建了临时对象给name
,与第二种情况一样,它们也是可以以移动的方式加入names
的。
所以以上第二、三种情况都可以被优化。
优化版本
当传入的参数是左值时,使用拷贝。当传入的参数是右值时,使用移动。那么基于通用引用的std::forward
转换便是一个比较好的方式:
1 | template<typename T> |
使用上面这个函数模板后,第一种情况依然以拷贝方式加入全局变量names
。而第二、三种情况则是以移动的方式加入names
。
加入重载
下面假设,用户可以查询索引的方式传入字符串,那么logAndAdd
就需要一个重载版本:
1 | std::string nameFromIdx(int idx); // return name corresponding to idx new overload |
那么要调用该函数的方式如下:
1 | logAndAdd(22); // calls int overload |
但如果传入一个变量,便会出错:
1 | short nameIdx; |
这是因为,当传入的参数是short
时,函数模板就将T
推导成了short
,虽然int
版本的重载函数也可以接受short
类型,但是函数模板的推导结果更为准确。最终short
无法构造出std::string
而导致报错。