假设我们有一个类Box,如下所示:
struct Base {}
template<typename T>
struct Box : Base
{
template<typename... Args>
Box(Args&&... args)
: t(forward<Args>(args)...)
{}
T t;
}
然后我们有一个函数MakeBox:
template<typename X>
Base* MakeBox(X&& x)
{
return new Box<???>(forward<X>(x));
}
从调用MakeBox的参数中推导出类型X
。
然后,我们需要从X以某种方式计算适当的“存储类型”参数T。
我想如果我们只是天真地使用:
return new Box<X>(forward<X>(x));
然后这会导致问题。
显然std::bind
和std::function
需要处理这些问题,他们是如何做到的?
std::decay
对此有帮助吗?
答案 0 :(得分:3)
如果我理解你想要达到的目标,那么你需要使用std::decay
。假设您要向S
提供类型为MakeBox()
的对象,则将以这样的方式解析通用引用X&&
,以使函数参数类型为S&
或{ {1}}取决于你的论证是(分别)是左值还是右值。
为实现这一目标并且由于C ++ 11规则的通用引用,在第一种情况下,模板参数将被推导为S&&
(这里X=S&
不能作为{的参数{1}},因为你的成员变量必须是一个对象,而不是一个对象引用),而在第二种情况下,它将被推导为X
(这里Box<>
可以作为参数X=S
)。通过应用X
,您还会隐式地将Box<>
应用于推断类型std::decay
,然后将其作为模板参数提供给std::remove_reference
,您将确保X
永远等于Box<>
而永远不会X
(请注意,S
永远将被推断为S&
,它将是X
或S&&
)。
S
如果您有兴趣,这是斯科特迈耶斯的一个非常好的课程,他解释了普遍参考的行为:
Scott Meyers on universal references
P.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;
}
原来是更好的选择。问题海报的问题@Andrew Tomazos FathomlingCorps,他指出了这一点,以及@Mankarse,他在对原始问题的评论中首次提出它。
答案 1 :(得分:1)
对于提供的示例,(1)
执行您想要的操作并存储该值。对于其他情况(例如当x
是数组时),您可以使用std::decay
将其衰减为指针并存储它。