获得适当的存储值类型?

时间:2012-12-30 07:53:07

标签: c++ c++11

假设我们有一个类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::bindstd::function需要处理这些问题,他们是如何做到的?

std::decay对此有帮助吗?

2 个答案:

答案 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& ,它将是XS&&)。

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将其衰减为指针并存储它。