一个 MD5 计算类(以下代码仅为示例,移除了大部分与主题无关的实现):
class MD5 {
public:
MD5(ifstream& in); // 构造函数
void calc(ifstream& in); // MD5 计算函数
std::string md5(void); // 获取 MD5 值
};
MD5::MD5(ifstream& in){
calc(in);
}
调用方式:
ifstream ifs("file.txt");
MD5 md5(ifs);
cout << md5.md5() << endl;
不可通过以下方式调用:
MD5 md5(ifstream("file.txt"));
因为 ifstream("file.txt")
是一个右值,无法传递给左值引用 ifstream&
。
解决方法之一是使用右值引用:
MD5(ifstream&& in){
calc(in);
}
但这样会导致 MD5 md5(ifs);
无法调用,因为 ifs
是左值。
解决方法之二是使用完美转发:
template<typename T>
MD5(T&& in){
calc(forward<T>(in));
}
template<typename T>
void calc(T&& in){
// ...
}
这样既可以接受左值也可以接受右值,实现了完美转发。
值得注意的是,因为构造函数调用了 calc
函数,所以 calc
函数也需要使用完美转发。
否则 MD5 md5(ifstream("file.txt"));
会导致编译错误。
(在 calc
函数中,不需要关心 in
具体是左值还是右值,当作普通引用即可)
因为原本 calc
函数接受的是左值引用,无法接受右值。
补充
这里的实现不需要维持 ifstream
的生命周期,对于其他场景下,需要维持右值的生命周期,可以使用 std::move
来转移右值。此处不赘述。