2017-12-20 15 views
0

質問:C++ラッパーテンプレート:テンプレートパラメータとして渡す方法は? C++テンプレートの達人へ

#include <algorithm> 
#include <iostream> 
#include <memory> 
#include <string> 
#include <unordered_map> 
#include <vector> 

template <typename T> 
class DumbPtrVec 
{ 
    std::vector<T*> m_vec; 
public: 
    using handle = size_t; 

    ~DumbPtrVec() { 
    std::for_each(begin(m_vec), end(m_vec), [](T* p){ delete p; }); 
    } 

    handle AddElement(T* p) { 
    const handle index = m_vec.size(); 
    m_vec.push_back(p); 
    return index; 
    } 

    T* GetElement(const handle& i) { 
    T* p = (i < m_vec.size())? m_vec[i] : nullptr; 
    return p; 
    } 
}; 

template <typename T> 
class SmartPtrVec 
{ 
    std::vector<std::shared_ptr<T>> m_vec; 
public: 
    using handle = std::weak_ptr<T>; 

    handle AddElement(T* p) { 
    m_vec.emplace_back(p); 
    return m_vec.back(); // gets converted to weak_ptr 
    } 

    T* GetElement(const handle& i) { 
    T* p = (i.expired())? nullptr : i.lock().get(); 
    return p; 
    } 
}; 

template <typename T, template<typename> typename STORAGE> 
class Storage 
{ 
    STORAGE<T> m_values; 
public: 
    using handle = typename STORAGE<int>::handle; 

    handle AddValue(T* v) { return m_values.AddElement(v); } 
    T* GetValue(handle h) { return m_values.GetElement(h); } 
}; 

int main() 
{ 
    constexpr int N = 13; 

    Storage<int, DumbPtrVec> d; 
    auto dh = d.AddValue(new int(N)); 
    std::cout << *d.GetValue(dh) << " == " << N <<std::endl; 

    Storage<int, SmartPtrVec> s; 
    auto sh = s.AddValue(new int(N)); 
    std::cout << *s.GetValue(sh) << " == " << N << std::endl; 

    return 0; 
} 
:私はダムやスマートのいずれかのポインタのベクトルでいくつかの値型のストレージを実装する2つのテンプレート「政策」(これは正しい用語であるかどうかわからないが)、作成した

これまでのところすべてうまくいきます。
次に、要素「ハンドル」を一意の文字列で置き換え、文字列をハンドルに戻すルックアップテーブルを保持するテンプレートラッパーを追加しました。このクラスがDumbPtrVecまたはSmartPtrVecクラスのいずれかから明示的に派生している場合、すべてが機能します。 SmartPtrVec用:

template <typename T> 
class StringHandleWrapper : SmartPtrVec<T> 
{ 
    using super = typename SmartPtrVec<T>; 
    using Str2HandleMap = std::unordered_map<std::string, typename super::handle>; 

    Str2HandleMap m_Name2HandleMap; 

public: 
    using handle = std::string; 

    handle AddElement(T* p) { 
     typename super::handle elem = super::AddElement(p); 

     static int counter = 0; 
     std::string uuid = std::to_string(++counter); 

     m_Name2HandleMap[uuid] = elem; 
     return uuid; 
    } 

    T* GetElement(const handle& uuid) { 
     auto it = m_Name2HandleMap.find(uuid); 
     return (it != m_Name2HandleMap.end())? super::GetElement(it->second) : nullptr; 
    } 
}; 

と成功呼び出し:

Storage<int, StringHandleWrapper> s; 
std::string handle = s.AddValue(new int(N));  

しかし、それはDumbPtrVecのいずれか、またはを包むことができるように、私は、StringHandleWrapperに、STORAGE、2番目のテンプレートパラメータを追加する方法を見つけ出すことはできません

template <typename T, template<typename> typename STORAGE> 
class StringHandleWrapper : STORAGE<T> 
{ 
    using super = typename STORAGE<T>; 
//... rest unchanged 
:私は StringHandleWrapperに変更した場合は SmartPtrVec ...

コンパイラは「少なすぎるテンプレート引数」文句を言うと、私は、Storageクラスをインスタンス化する方法を見つけ出すことはできません。

Storage<int, StringHandleWrapper<SmartPtrVec>> s; 

私は、単純な何かが欠けてる願っています...

はありがとう私の長い質問を見てあなたの時間を取るために!私は、例えば、2つの単一のパラメータテンプレート

template<typename T> using StringDumbHandleWrapper = StringHandleWrapper<T, DumbPtrVec>; 
template<typename T> using StringSmartHandleWrapper = StringHandleWrapper<T, SmartPtrVec>; 

を導入し、Storageインスタンス化で新しい名前を使用するために必要な

答えて

0

ただ答えを(それは確かに簡単だった)が発見しました

Storage<int, StringDumbHandleWrapper> s; 

長い質問にはあまりにも多く... :)

1

が部分的引数アプリケーションのテンプレートの別のレベルを作成します。

Storage<int, Apply<StringHandleWrapper, SmartPtrVec>::type> s; 

template <template <typename, template<typename> typename> class W, 
      template <typename> typename S> 
struct Apply 
{ 
    template <typename T> using type = W<T, S>; 
}; 

を次に、このようなStorageをインスタンス化

+0

ありがとうございます!知っておいてよかった。 – Boris

関連する問題