创建通用引用的重载函数,但很多时候还是会调用到通用引用函数,这会让人很迷惑。
普通版本
假设我们要实现一个函数,用于存入传递进来的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而导致报错。