2015-09-25 49 views
2

我有一個模板容器類,需要將附加信息與用戶指定類型的每個實例相關聯。C++類包裝和放置新

容器指定包含指定類型和附加信息的包裝結構...

template<typename T> class Container 
{ 
    ... 

    struct Wrapper 
    { 
     T mType; 
     int mInfo; 
    }; 
} 

在初始化時,容器被填充有包裝(即,包裝*)的動態分配的實例。用戶可以彈出()一個實例,容器將會返回一個轉換爲T *。用戶可以推送()一個實例,容器將轉回Wrapper *。

這工作正常,如果數據類型可以默認構造。但是,情況並非總是如此,我想讓用戶提供一個在初始化期間調用的分配函數,該函數構造了它喜歡的數據類型。容器可以爲功能要求特定的簽名。

template<typename T> template<typename F> void Container<T>::init(F allocator); 

我在努力的是如何在函數分配數據類型時分配Wrapper。我想過使用placement new,容器爲Wrapper分配足夠的空間,並將地址傳遞給函數以執行新的數據類型放置。

有沒有更清晰的方法去解決這個問題?

+0

最好是寫代碼,然後解釋類應該做的事情。爲什麼要創建實例,如果有可能推/流? –

+0

只能推動/彈出屬於容器的對象。也就是說,容器需要附加信息進行裝飾的對象。用戶看到T *,而容器看到Wrapper *。 – user1715664

+1

我同意BЈовић:最好是寫代碼。但是,從我所能理解的情況來看,你需要一個包裝器中的構造函數,它需要你的T. – noxmetus

回答

0

您不需要爲此分配功能。相反,你需要像標準容器中的emplace_push這樣的東西。

0

我只是將用於構造T的參數添加爲Container的模板參數,並使用它們構造T.爲了允許T對象的動態構造,容器構造函數接受作爲參數的函數指針爲參數的創建排名的整數,並且對於T構造的默認參數,並返回參數的元組對於T構造(std::tuple<U...> (*getInitParam)(int rank, U... params)):

template<typename T, typename ...U> 
class Container { 
    struct Wrapper { 
     T mType; 
     int mInfo; 

     Wrapper(int mInfo, U... params): mType(params...), mInfo(mInfo) {} 
    }; 

    std::stack<Wrapper *> stack; 

    int get_mInfo() { 
     static int info = 0; 

     return info++; 
    } 
    std::tuple<U...> (*getInitParam)(int rank, U... params); 

public: 
    T* pop() { 
     // should control stack is not empty 
     Wrapper *w = stack.top(); 
     stack.pop(); 
     return &w->mType; 
    } 
    void push(T* type) { 
     char *p = reinterpret_cast<char *>(type); 
     p -= offsetof(Wrapper, mType); 
     Wrapper *w = reinterpret_cast<Wrapper *>(p); 
     // would need to control that *w is a valid Wrapper 
     stack.push(w); 
    } 
    void init(int n, U... params) { 
     std::tuple<U...> orig = std::make_tuple(params...); 
     for (int i=0; i<n; i++) { 
      if (getInitParam != nullptr) { 
       std::tie(params...) = orig; 
       std::tuple<U...> tparams = (*getInitParam)(i, params...); 
       std::tie(params...) = tparams; 
      } 
      Wrapper *w = new Wrapper(get_mInfo(), params...); 
      stack.push(w); 
     } 
    } 
    Container(std::tuple<U...> (*getInitParam)(int rank, U... params) = nullptr) 
     : getInitParam(getInitParam) {} 
    ~Container() { 
     while(! stack.empty()) { 
      Wrapper *w = stack.top(); 
      delete w; 
      stack.pop(); 
     } 
    } 
}; 

用例:

std::tuple<size_t, char> doInit(int i, size_t szmin, char c) { 
    return std::make_tuple(szmin + i, c); 
} 

int main() { 
    Container<std::string, size_t, char> cont(&doInit); 
    cont.init(10, 5, 'x'); 

    std::string* str0 = cont.pop(); 
    std::string* str = cont.pop(); 
    std::cout << *str0 << std::endl; 
    std::cout << *str << std::endl; 

    *str0 = "bar"; 

    cont.push(str0); 
    cont.push(str); 

    str0 = cont.pop(); 
    str = cont.pop(); 

    std::cout << *str << std::endl; 
    cont.push(str); 
    cont.push(str0); 
    return 0; 
} 

Ť他正確地輸出:

xxxxxxxxxxxxxx 
xxxxxxxxxxxxx 
bar 

仍然有實行明覆用法,但它應該是一個起點......

+0

是的,這適用於T的構造函數參數是靜態的。考慮一個簡單的例子,其中T的每個實例都需要一個唯一的ID作爲其構造函數的一部分。這就是爲什麼我希望用戶能夠通過某種分配器。 – user1715664

+0

@ user1715664:我想我可以通過一個可選函數來滿足這個需求,該函數計算用於T對象構造的參數。請參閱編輯的文章 –