【发布时间】:2015-01-19 15:56:26
【问题描述】:
我正在尝试用 C++ 进行完美转发,因此我编写了以下快速而肮脏的代码来测试这一点。
class CValue
{
public:
CValue(int i) :
m_i(i)
{
printf("Default constructor called!\r\n");
}
CValue(const CValue& src) :
m_i(src.m_i)
{
printf("Copy constructor called!\r\n");
}
CValue(CValue&& src) :
m_i(src.m_i)
{
printf("Move constructor called!\r\n");
}
CValue& operator=(const CValue& src)
{
m_i = src.m_i;
printf("Copy assignment called!\r\n");
return *this;
}
CValue& operator=(CValue&& src)
{
m_i = src.m_i;
printf("Move assignment called!\r\n");
return *this;
}
int m_i;
};
template <typename T>
void PerfectForwarding(T&& tValue)
{
T tValue1 = tValue;
tValue1.m_i = 10;
}
int _tmain(int argc, _TCHAR* argv[])
{
CValue v(0);
PerfectForwarding(v);
printf("%d\r\n", v.m_i);
return 0;
}
当我将此代码作为控制台应用程序构建和运行时,我得到的答案是 10,而我期待的是 0。
好像是这样一行:
T tValue1 = tValue;
在PerfectForwarding函数中被解析为:
CValue& tValue1 = tValue;
代替:
CValue tValue1 = tValue;
所以编译器将 T 解析为 CValue&,这是我没想到的。
我尝试通过显式声明模板参数类型来从 _tmain 调用函数,即
PerfectForwarding<CValue>(v);
但是编译失败并出现以下错误:
error C2664: 'void PerfectForwarding<CValue>(T &&)' : cannot convert
argument 1 from 'CValue' to 'CValue &&'
with
[
T=CValue
]
You cannot bind an lvalue to an rvalue reference
我可以通过将 PerfectForwarding 函数中的行更改为以下内容来强制执行所需的行为:
typename std::remove_reference<T>::type tValue1 = tValue;
但我认为这没有必要。通过引用折叠规则,参数 (T&&) 的类型应该变为 CValue&(如 T&& & -> T&),但 T 本身应该只是 CValue,确定吗?这是 VC12 编译器处理右值引用的错误,还是我误解了右值引用和模板?
我在调试中使用 Visual Studio 2013(VC12 编译器)并关闭所有优化。
【问题讨论】:
-
在链接的欺骗中,专门扫描“通用”(或“转发”)引用。
-
@sehe,我认为stackoverflow.com/q/14302849/3093378 更适合骗子,即使就其标题而言也是如此。这个问题实际上与移动语义无关。
-
参见Effective Modern C++ 第 1、24 和 28 项:...这是模板类型推导中唯一将 T 推导出为引用的情况
-
@jrok,是的,对不起,我期待的答案是 0,而不是 4。我已编辑问题以更正此问题。
-
@vsoftco 这看起来也很有帮助!您可以添加它(我认为?)(我认为该特定问题不会最终以自然查询来解释此 OP 所具有的这个问题的答案,但是是的,它的范围更简洁)
标签: c++ templates c++11 perfect-forwarding