2015-10-06 77 views
1

说我有下面的代码:如何在非泛型类型上实现完美转发?

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类型的参数,所以它的函数声明不应该反映这个吗?

有没有什么办法可以实现一个功能的完美转发,同时在语法上证明它只接受一种变量?我基本上需要一个函数来自动区分特定参数类型的左值和右值版本。

回答

3

您的选项是

  1. 使用两个重载(又名 “做什么vector::push_back”):

    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)); 
    } 
    

选项2费用高达一个额外的举动,但移动shared_ptr s是便宜,因为你不需要触摸引用计数。选项1是有效的,但受到组合爆炸的影响。选项3也是有效的,但更难以阅读和维护。