2015-10-06 74 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也是有效的,但更難以閱讀和維護。