2017-12-20 11 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; 
} 
: 나는 두 개의 템플릿 "정책"을 만들었습니다
바보 또는 스마트 포인터 중 하나의 벡터에 어떤 값 유형의 스토리지를 구현, (이 올바른 용어입니다 있는지 확실하지 않습니다)

모든 것이 제대로 작동합니다.
그런 다음 템플릿 "래퍼"를 추가했습니다.이 래퍼는 "handle"요소를 고유 한 문자열로 바꾸고 문자열을 핸들로 다시 변환하기위한 참조 테이블을 유지합니다. 이 클래스가 DumbPtrVec 또는 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; 
    } 
}; 

성공적인 호출 : SmartPtrVec에 대한

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

그러나 나는 그것이 DumbPtrVec 또는 중 하나를 포장 할 수 있도록, StringHandleWrapper에, 두 번째 템플릿 매개 변수, STORAGE를 추가하는 방법을 알아낼 수 없습니다

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; 

을 나는 간단하게 뭔가를 누락 희망 ...

감사합니다 내 긴 질문을 보면서 시간을내어 주셔서 감사합니다!

답변

0

그냥 (이것은 실제로 간단했다) 답을 발견
나는 두 개의 단일 매개 변수 템플릿

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

을 소개하고 Storage 인스턴스화, 예를 들어,의 새로운 이름을 사용하는 데 필요한

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