2012-12-13 69 views
1

問題是關於在MS Visual C++ 11中開發的代碼,只能訪問STL,沒有提升。如何在STL容器中存儲模板化的異構對象

有一個包裝模板類,大致與此頭:

template <typename Payload> 
class Wrapper { 
    Payload p; 
    std::string src; 
    Wrapper(std::string, Payload); 

    Payload get();  // returns payload 
    void set(Payload); // replaces payload 
    void operator()(); // uses payload 
} 

Payload可以是任何東西 - 指針,詮釋,甚至重的物體。

後來,Wrapper需要在容器中,像std::vector - 但不管它們的具體參數類型。這給我帶來麻煩,因爲容器需要同質元素。

我已經嘗試了基類建議like this from KennyTM,但它給了我一些問題與方法get()set() - 從載體使用時,因爲元素,看起來像一個基類,如果在所建議的方式使用那些需要投(?)那個答案。

+1

你需要類型擦除類,比如'boost :: any',你可以自己實現,所以你可以避免Boost。 – Nawaz

+1

KennyTM的解決方案僅適用於實際可以使用虛擬功能的情況。你不能在這裏因爲你的函數的返回類型是不兼容的。另外,對象根據模板參數的不同也不重要。它們仍然是不同尺寸的不同類型,這對集裝箱來說是最重要的。 – pmr

回答

3
template<typename Payload> 
struct Wrapper; 

struct WrapperBase { 
    std::string src; 
    WrapperBase(std::string s):src(s) {} 
    template<typename Payload> 
    Payload get() const; 
    template<typename Payload> 
    void set(Payload); 
    virtual void operator()() = 0; // uses payload 
}; 

template <typename Payload> 
struct Wrapper { 
    Payload payload; 
    Wrapper(std::string s, Payload p):WrapperBase(s),payload(p) {} 

    Payload get() const { return payload; };  // returns payload 
    void set(Payload p) { payload = p; }; // replaces payload 
    virtual void operator()() override; // todo 
} 

template<typename Payload> 
Payload WrapperBase::get() const { 
    Assert(dynamic_cast<Wrapper<Payload> const*>(this)); 
    return static_cast<Wrapper<Payload> const*>(this)->get(); 
} 
template<typename Payload> 
void WrapperBase::set(Payload p) { 
    Assert(dynamic_cast<Wrapper<Payload>*>(this)); 
    static_cast<Wrapper<Payload>*>(this)->set(p); 
} 

一個WrapperBase的用戶,如果他們想設置/獲取有效載荷,需要知道有效負載的類型是什麼。如果您不知道,您可以使用dynamic_cast<Wrapper<Payload>*>來判斷給定的WrapperBase是否爲特定種類。

這沒有價值語義,所以你會想要存儲一個vector智能指針WrapperBase而不是實際的實例。 std::shared_ptrstd::unique_ptr是行爲非常不同的優秀候選人。

如果有一個有限的Payloads有界集合,訪問者模式可以工作。

如果您需要值語義,存儲實際有效負載的pImpl模式可以使用手動operator=來克隆pImpl

詢問「你是否持有類型T」是可能的,但通常類似於dynamic_cast

+0

有趣,所以我錯過了基類中方法的模板,除此之外。謝謝,現在嘗試。 –

5

爲此,您需要使用某種類型的擦除。從最基本的(提供基本類型,通過指向基地的存儲元素)到像boost ::任何你可以選擇的更好的解決方案(我知道你沒有提到提升,但你總是可以看看實現) 。或者,如果已知有效負載集合且相對較小,但可能會使用變體方法(類似於boost ::變體),但這對於單次使用可能較難實現。