C ++包装器模板:如何将其作为模板参数传递?

时间:2017-12-20 18:34:55

标签: c++ templates

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”,并保留一个查找表,用于将字符串转换回句柄。如果此类明确派生自DumbPtrVecSmartPtrVec类,则一切正常,例如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));    

但我无法弄清楚如何将第二个模板参数STORAGE添加到StringHandleWrapper,以便它可以包装DumbPtrVecSmartPtrVec中的任何一个。 ..
如果我将StringHandleWrapper更改为:

template <typename T, template<typename> typename STORAGE>
class StringHandleWrapper : STORAGE<T>
{
    using super = typename STORAGE<T>;
//... rest unchanged

然后我无法弄清楚如何实例化Storage类,因为编译器抱怨“模板参数太少”:

Storage<int, StringHandleWrapper<SmartPtrVec>> s;

我希望我错过了一些简单的事情......

感谢您花时间浏览我的长篇问题!

2 个答案:

答案 0 :(得分:1)

为部分参数应用创建另一个级别的模板:

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

然后像这样实例化Storage

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

答案 1 :(得分:0)

刚刚找到答案(确实很简单):
我需要介绍两个单参数模板

module.exports

并在module.exports = { plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } }), ] } 实例化中使用新名称,例如

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

长期以来的问题...... :)