实际上,这是一个非常好的问题。到目前为止,我也一直在使用通用参考技巧加上enable_if
锤子。在这里,我提出了一个不使用模板并使用左值转换作为替代方案的解决方案。
ofstream
下面是一个真实的例子,使用在 C++98 中不可能(或非常困难)的已知就地使用示例出现这种情况(我ostringstream
在示例中使用以使其更清楚)。
首先你会看到一个左值引用的函数,这在 C++98 中很常见。
#include<iostream>
#include<sstream>
struct A{int impl_;};
std::ostringstream& operator<<(std::ostringstream& oss, A const& a){
oss << "A(" << a.impl_ << ")"; // possibly much longer code.
return oss;
}
// naive C++11 rvalue overload without using templates
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
oss << "A(" << a.impl_ << ")"; // ok, but there is code repetition.
return oss;
}
int main() {
A a{2};
{// C++98 way
std::ostringstream oss;
oss << a;
std::cout << oss.str() << std::endl; // prints "A(2)", ok"
}
{// possible with C++11, because of the rvalue overload
std::cout << (std::ostringstream() << a).str() << std::endl; //prints "A(2)", ok
}
}
正如您在 C++11 中看到的,我们可以实现在 C++98 中无法实现的功能。那就是利用ostringstream
(或ofstream
)就地。现在来了 OP 问题,这两个重载看起来很相似,都可以合二为一吗?
一种选择是使用通用引用 ( Ostream&&
),并且可以选择使用 withenable_if
来约束类型。不是很优雅。
通过使用这个“真实世界”示例,我发现如果想对 lvalue ref 和 rvalue ref 使用相同的代码是因为你可能可以将一个转换为另一个!
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
return operator<<(oss, a);
}
这看起来像一个无限递归函数,但这并不是因为它oss
是一个左值引用(是的,它是一个左值引用,因为它有一个名称)。所以它会调用另一个重载。
您仍然需要编写两个函数,但其中一个函数的代码不必维护。
总之,如果“有意义”©将函数同时应用于(非 const)左值引用和右值,这也意味着您可以将右值转换为左值,因此您可以转发到单个函数。请注意,“有意义”取决于上下文和预期代码的含义,我们必须通过显式调用左值重载来“告诉”编译器。
我并不是说这比使用通用参考更好,我说这是一种替代方法,并且可以说意图更清楚。
此处可编辑代码:http: //ideone.com/XSxsvY。(欢迎反馈)