如果我正确理解您想要实现的目标,那么您需要使用std::decay
. 假设您提供 to 类型的对象S
,MakeBox()
通用引用X&&
将以这样的方式解析,以使函数参数成为类型S&
或S&&
取决于您的参数是(分别)是左值还是右值。
为了实现这一点并且由于通用引用的 C++11 规则,在第一种情况下,模板参数将被推断为X=S&
(这里X
不能作为 的参数Box<>
,因为您的成员变量必须是对象而不是对象参考),而在第二种情况下,它将被推断为X=S
(这里X
可以作为 的参数Box<>
)。通过应用std::decay
,您还将在将推导类型作为模板参数提供给 之前隐式应用于std::remove_reference
推导类型,您将确保它始终相等且永远不会(请记住,这永远不会像这里那样推导,它将是或X
Box<>
X
S
S&
X
S&&
S
S&
)。
#include <utility>
#include <type_traits>
#include <iostream>
using namespace std;
struct Base {};
template<typename T>
struct Box : Base
{
template<typename... Args>
Box(Args&&... args)
: t(forward<Args>(args)...)
{
}
T t;
};
template<typename X>
Base* MakeBox(X&& x)
{
return new Box<typename decay<X>::type>(forward<X>(x));
}
struct S
{
S() { cout << "Default constructor" << endl; }
S(S const& s) { cout << "Copy constructor" << endl; }
S(S&& s) { cout << "Move constructor" << endl; }
~S() { cout << "Destructor" << endl; }
};
S foo()
{
S s;
return s;
}
int main()
{
S s;
// Invoking with lvalue, will deduce X=S&, argument will be of type S&
MakeBox(s);
// Invoking with rvalue, will deduce X=S, argument will be of type S&&
MakeBox(foo());
return 0;
}
如果你有兴趣,这里是 Scott Meyers 的一个很好的课程,他解释了通用引用的行为:
Scott Meyers 谈通用参考
PS:这个答案已被编辑:我原来的答案建议使用std::remove_reference<>
,但std::decay
结果证明是一个更好的选择。感谢问题海报@Andrew Tomazos FathomlingCorps,他指出了这一点,以及@Mankarse,他首先在对原始问题的评论中提出了这个问题。