问题描述
#include <assert.h>
#include <iostream>
#include <typeinfo>
class Test{};
class Any {
public:
template<typename DataType>
explicit Any(DataType&& in) {
Test t;
std::cout
<< typeid(t).name() << " "
<< typeid(in).name() << " "
<< typeid(test()).name();
std::cout << " move";
}
template<typename DataType>
explicit Any(const DataType& in) {
Test t;
std::cout
<< typeid(t).name() << " "
<< typeid(in).name() << " "
<< typeid(test()).name();
std::cout << " copy";
}
};
int main()
{
Test t;
Any a(t);
}
编译命令是
g++ main.cpp -std=c++11
输出是
4Test 4Test F4TestvE move
非常感谢。
解决方法
- 为什么 c++ 选择移动构造而不是复制构造? “t”是 Test 的一个实例,它不是右值。
第一个构造函数重载采用 forwarding reference 并且可以接受左值和右值。 (因此它不是移动构造函数。)对于 Any a(t);
它是完全匹配,而对于第二个重载 t
需要转换为 const
。
- 为什么 typeid(in) 和 typeid(Test()) 不一样?它们都是右值。
Test()
是一个函数类型,它返回 Test
并且不带任何东西,因此 typeid(Test())
给出了不同的结果。
您的移动变体被调用的原因是它的签名实际上并不需要传递右值引用。
如果 U = T const&
,那么 U&&
将是 T const&
,而不是 T&&
。在您的情况下,DataType
绑定到 Test&
,而不是像您预期的那样绑定到 Test
。因此 &&
会折叠并且什么也不做。如果您添加将通过的 static_assert(std::is_same_v<DataType,Test&>);
,您可以看到这一点。
如果您用固定类型替换模板,即 Test&&
而不是 DataType&&
,您的函数将被调用。
查看 reference,参考折叠部分。