2014-03-02 36 views
3

考慮具有privatestd::vector數據成員的類:完美轉發到數據成員的成員函數?

class MyClass 
{ 
    private: 
     std::vector<double> _data; 
    public: 
     template <class... Args> 
     /* something */ insert(Args&&... args) /* something */ 
     { 
      return _data.insert(std::forward<Args>(args)...); 
     } 
}; 

什麼是正確的語法(使用C++ 14自動/可變參數模板/前進...)來的_data一個給定的功能轉移到MyClass (例如insert),併爲用戶提供相同的界面?

+0

你指的是你的'insert'包裝的返回類型? 'decltype(auto)' – dyp

+0

參數列表後的'something'應該包含正確的cv-和ref-qualifiers和exception-specification? – dyp

+1

「將_data的給定函數傳遞給MyClass的正確語法是什麼」 - > Erm,什麼? – fredoverflow

回答

5

正確的語法是這樣的:

class MyClass 
{ 
    private: 
     std::vector<double> _data; 
    public: 
     template <class... Args> 
     decltype(auto) insert(Args&&... args) 
     { 
      return _data.insert(std::forward<Args>(args)...); 
     } 
}; 

但是,你實際上並不需要C++ 14做。您可以使用C++ 11語法。

class MyClass 
{ 
    private: 
     std::vector<double> _data; 
    public: 
     template <class... Args> 
     auto insert(Args&&... args) 
     -> decltype(_data.insert(std::forward<Args>(args)...)) 
     { 
      return _data.insert(std::forward<Args>(args)...); 
     } 
}; 
+0

或者常規的C++:'std :: vector :: iterator insert(...)' – 0x499602D2

+0

我認爲OP希望包裝函數也具有相同的異常規範和cv-限定條件(也許可以使用ref-qualifiers,儘管這與'std :: vector'不相關) –

+3

@JonathanWakely也許有一天我們會有'noexcept(auto)':P – Rapptz

2

真正着一個成員函數的調用,一個必須考慮的正確轉發爲成員呼叫*this值的必要性。

以下:

template<typename Type> 
struct Fwd { 
    Type member; 

    template<typename ...Args> 
    decltype(auto) Func(Args&&... args) 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) 
     { return member.Func(std::forward<Args>(args)...); } 
}; 

是足夠的轉發參數和異常規範,因爲你可能已經猜到了。但它不足以完全向前*this

struct S { 
    // These overloads are reachable through Fwd<S>::Func(). 
    void Func(int) & {} 
    void Func(int&&) & {} 

    // These other overloads are not. 
    void Func(int) const&; 
    void Func(int&&) const&; 
    void Func(int) volatile&; 
    void Func(int&&) volatile&; 
    void Func(int) const volatile&; 
    void Func(int&&) const volatile&; 
    void Func(int) &&; 
    void Func(int&&) &&; 
    // (These are rather uncommon, just provided for completude.) 
    void Func(int) const&&; 
    void Func(int&&) const&&; 
    void Func(int) volatile&&; 
    void Func(int&&) volatile&&; 
    void Func(int) const volatile&&; 
    void Func(int&&) const volatile&&; 
}; 

有此問題的兩個解決方案。一種方法是簡單地手動創建的每一個其他可能的過載,這可能與宏:

#define FWD(member, Func) \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) & \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return member.Func(std::forward<Args>(args)...); } \ 
    \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) const& \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return member.Func(std::forward<Args>(args)...); } \ 
    \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) volatile& \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return member.Func(std::forward<Args>(args)...); } \ 
    \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) const volatile& \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return member.Func(std::forward<Args>(args)...); } \ 
    \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) && \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return std::move(member).Func(std::forward<Args>(args)...); } \ 
    \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) const&& \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return std::move(member).Func(std::forward<Args>(args)...); } \ 
    \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) volatile&& \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return std::move(member).Func(std::forward<Args>(args)...); } \ 
    \ 
    template<typename ...Args> \ 
    decltype(auto) Func(Args&&... args) const volatile&& \ 
     noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \ 
     { return std::move(member).Func(std::forward<Args>(args)...); } 

template<typename Type> 
struct Fwd { 
    Type member; 
    FWD(member, Func) 
}; 

另一解決方案是完全避免一個成員函數和使用一個免費的功能:

template<typename Fwd, typename ...Args> 
decltype(auto) Func(Fwd&& fwd, Args&&... args) 
    noexcept(noexcept(std::forward<Fwd>(fwd).Func(std::forward<Args>(args)...))) { 
    return std::forward<Fwd>(fwd).Func(std::forward<Args>(args)...); 
}