【发布时间】:2011-04-05 05:52:31
【问题描述】:
如果你有这个功能
template<typename T> f(T&);
然后尝试调用它,比如说像这样的右值
f(1);
为什么不直接将 T 推导出为 const int,使参数成为 const int& 从而可绑定到右值?
【问题讨论】:
标签: c++ forwarding c++03
如果你有这个功能
template<typename T> f(T&);
然后尝试调用它,比如说像这样的右值
f(1);
为什么不直接将 T 推导出为 const int,使参数成为 const int& 从而可绑定到右值?
【问题讨论】:
标签: c++ forwarding c++03
这在the document 中被提及为潜在的解决方案,我在recent C++0x forwarding question 中链接。
它会工作得相当好,但它会破坏现有代码。考虑(直接来自文档):
template<class A1> void f(A1 & a1)
{
std::cout << 1 << std::endl;
}
void f(long const &)
{
std::cout << 2 << std::endl;
}
int main()
{
f(5); // prints 2 under the current rules, 1 after the change
int const n(5);
f(n); // 1 in both cases
}
或者
// helper function in a header
template<class T> void something(T & t) // #1
{
t.something();
}
// source
#include <vector>
void something(bool) // #2
{
}
int main()
{
std::vector<bool> v(5);
// resolves to #2 under the current rules, #1 after the change
something(v[0]);
}
这也无法转发值类别(左值或右值),这在 C++03 中不是什么大问题。但是由于这个修复只能在 C++0x 期间完成,所以我们在转发时有效地将自己与右值引用隔离开来(一件坏事)。我们应该努力寻求更好的解决方案。
【讨论】:
是的,但前提是你声明f 接受T const &。
template <typename T> void f(T &);
template <typename T> void g(T const &);
void x() { f(1); } // error: invalid initialization of non-const reference
void y() { g(1); } // no error
如果你声明 both f(T &) 和 f(T const &),它会选择 const 限定的:
template <typename T> void f(T &);
template <typename T> void f(T const &);
void x() { f(1); } // no error, calls f(T const &)
现在您可能会说“在第一个示例中,为什么它会为调用 f 生成一个 int 类型的临时文件,而它可以生成一个 @ 类型的临时文件987654329@ 并编译了代码?”我为您提供的最佳答案是,当参数不是整数常量时,这与重载解析行为不一致。
【讨论】:
1 的类型为 int。如果您声明了int i = 1,那么它将选择非常量方法,因为i 不是常量。因此,为了保持一致性,这里也是这样做的,只是对于右值,这是一个错误。
1应该是int const类型,因为哎,我改不了!然而,这不是标准所说的那样,因此不是。至于禁止引用 rvalue 我永远不会喜欢它,从 C++ 哲学的角度来看这是没有意义的转发,对于类似“sink”的行为等),毕竟,为什么我不能修改一个临时的并对此感到满意呢?但标准就是法律,因此是一致的