c++ 避免重载通用引用函数

贪婪的函数模板 (通用引用函数模板)
函数模板是贪婪的,它会根据调用方的需求,实例化任意多个具体的函数版本,完全由客户端决定,这个也一度被人诟病,模板会导致代码膨胀。函数模板通过类型推导几乎可以匹配任何类型的输入参数,如果设计了其他的重载函数,重载决议的时候可能会发生意想不到的匹配结果。

这个情况也存在于标准库里面,比如对 std::list 调用 std::sort 算法会触发编译错误,错误信息还比较扯淡,这个也是 C++20 引入 concept 的根本原因。

代码示例 :
#include
#include
#include

template void print(T &&t) {
std::cout << “calls print(T &&t): ” << std::forward(t) << ‘\n’;
}

void print(int t) { std::cout << “calls print(int t): ” << t << ‘\n’; }

int main() {
// template void print(T &&t)
// instantiate for type std::complex and std::string
std::complex c{3, 4};
std::string s{“hello”};
print(c); // calls print(T &&t): (3,4)
print(s); // calls print(T &&t): hello

// template void print(T &&t)
// instantiate for type for short int and unsigned int
short si = 42;
unsigned int ui = 42;
print(si); // calls print(T &&t): 42
print(ui); // calls print(T &&t): 42

// int exact match void print(int t)
int i = 42;
print(i); // calls print(int t): 42
print(42); // calls print(int t): 42

return 0;
}
当通用引用函数与具体函数构成重载的时候 (自由函数):
去掉修饰符,当参数类型完全匹配的时候,具体函数的匹配优先级高
其它任何情况下,通用引用函数都会贪婪的去优先匹配,可能会发生意想不到的结果
通用引用函数,通过类型推导,几乎可以匹配任何类型的入参,很容易被误用
通用引用函数与对象构造
为类设计通用引用的构造函数同样会发生重载决议问题,而且问题会变得比自由函数更加复杂,不建议这么做,也没必要这么做。但是设计一个不定参数的函数模板工厂方法还是很有用的,比如 PASSKEY 惯用法。

代码示例 :

#include
#include
#include

class Job {
public:
Job(const std::string &name) : name_{name} { std::cout << “call ctor1\n”; }
template Job(T &&name) : name_(std::forward(name)) {
std::cout << “call ctor2\n”;
}

private:
std::string name_;
};

int main() {
// case 1: must match the const qualifier
const std::string name0{“j0”};
Job j0(name0); // call ctor1

std::string name1{“j1”};
Job j1(name1); // call ctor2
Job j2(“j1”); // call ctor2

// case 2: the template ctor
// 1. does not prevents compiler to generate the copy ctor and move ctor
// 2. it is typically better matches than copy constructors for non-const lvalues
const Job j3{“j3”};
Job j4 = j3; // calls the compiler generate copy ctor (only for const lvalue)
Job j5 = std::move(Job{“j5”}); // calls the compiler generate move ctor
// Job j6 = j4; // try to call the template ctor, the better matches

return 0;
}
类的模板对象构造函数:

就是个一般的构造函数,不会阻止编译器生成拷贝构造函数与移动构造函数
类的模板对象构造函数,对于非 const 左值有更高的匹配优先级
为类设计通用引用构造函数,真的是一场灾难,尤其是涉及到继承关系的时候
总结
不要设计使用通用引用参数的函数(自由函数)
不要为类设计使用通用引用参数的构造函数 (成员函数)

为您推荐

返回顶部
首页
电子图书
视频教程
搜索
会员