如何在非泛型类型上实现完美转发?

时间:2015-10-06 00:44:32

标签: c++ c++11 move-semantics perfect-forwarding

说我有以下代码:

class Element;
typedef shared_ptr<Element> ElementPtr;

class Element
{
public:
    void add_child(const ElementPtr& elem);

private:
    vector<ElementPtr> children;
}

inline void Element::add_child(const ElementPtr& elem)
{
    children.push_back(elem);
};

我想更新add_child以使用完美转发功能。我尝试更改函数定义(和声明),因此请使用以下逻辑:

void Element::add_child(ElementPtr&& elem)
{
    children.push_back(forward<ElementPtr>(elem));
}

但是,对于任何一个参数elem都是左值的调用,它会崩溃。所以我想我会尝试使用模板并提出以下内容:

template <ElementPtr elem>
void Element::add_child(ElementPtr&& elem)
{
    children.push_back(forward<ElementPtr>(elem));
}

......但这不会编译。所以我改成了这个:

template <class T>
void Element::add_child(T&& elem)
{
    children.push_back(forward<T>(elem));
}

......哪些编译和工作,但似乎丑陋和不合适; add_child只会接受ElementPtr类型的参数,所以它的函数声明不应该反映这个吗?

有没有办法为函数实现完美转发,而在语法上证明它只接受一种变量?我基本上想要一个能够自动区分特定参数类型的左值和右值版本的函数。

1 个答案:

答案 0 :(得分:3)

您的选择

  1. 使用两个重载(又名&#34; vector::push_back做什么&#34;):

    void add_child(const ElementPtr& elem) { children.push_back(elem); }
    void add_child(ElementPtr&& elem) { children.push_back(std::move(elem)); }
    
  2. 使用单个重载,按值获取其参数:

    void add_child(ElementPtr elem) { children.push_back(std::move(elem)); }
    
  3. SFINAE。

    template <class T,
              class = std::enable_if_t<std::is_same<ElementPtr, std::decay_t<T>>{}>>
    void Element::add_child(T&& elem)
    {
        children.push_back(forward<T>(elem));
    }
    
  4. 选项2最多需要花费一个额外的移动,但移动shared_ptr是很便宜的,因为您不需要触摸引用计数。选项1是有效的,但受到组合爆炸的影响。选项3也很有效,但更难以阅读和维护。