【问题标题】:Remove last parameter from a parameter pack从参数包中删除最后一个参数
【发布时间】:2014-08-12 20:22:57
【问题描述】:

今天,在第 100 次使用同一个模板时,我想到了引入一个简单替换的想法。

代替

 QHash<int,QHash<int,QHash<int,int> > >

现在应该是:

 MultiKeyHash<int,int,int,int>

(不要与 QT 的 QMultiHash 类混淆)。

前三个参数是键的类型,最后一个参数是值的类型。

 MultiKeyHash<TKey1,TKey2,....,TKeyN,TValue>

我当前的实现如下所示:

template <typename... Args>
struct MultiKeyHash;

template <typename TKey1, typename... Args>
struct MultiKeyHash<TKey1, Args...> : QHash<TKey1,MultiKeyHash<Args...> > {

    typedef typename MultiKeyHash<Args...>::ValueType ValueType;
    const ValueType& value(const TKey1 &key1, const Args_Without_Last&... args) const {
          return operator[](key1).value(args...);
    }
};

template <typename TKeyN, typename TValue>
struct MultiKeyHash<TKeyN,TValue> : QHash<TKeyN,TValue> {
    typedef TValue ValueType;
};

在我想添加“值”方法之前,一切都按预期工作。我当然不能使用“Args”作为第二个参数(-pack)的类型。我是否必须为其制作一个函数模板,或者有什么办法吗?

我必须如何定义“值”方法才能像这样调用它:

value(key1,key2,...,keyn)

【问题讨论】:

  • 如果你可以改变你的设计/要求,使值类型成为模板的第一个参数,你就不需要弄清楚Args_Without_Last
  • value 不应该通过引用返回吗?返回多级哈希表的副本似乎很昂贵。我假设您在返回类型上省略了 &amp;,并且您无意使用“返回常量值”反模式。
  • @KerrekSB Args 的最后一个元素是值类型,而不是键类型之一。
  • @Casey:啊,当然。
  • @RSahu 不错的想法。也许我可以将值类型作为第一个参数,并用另一个模板反转参数顺序...

标签: c++ templates c++11 variadic-templates


【解决方案1】:

这是MultiHashKey 的工作版本。它使用QHash 的虚拟实现来进行测试。

#include <iostream>

// Dummy implementation of QHash for testing purposes.
template <typename TKey, typename TValue>
struct QHash
{
   void insert(const TKey& key, const TValue& val) {this->val = val;}
   const TValue& value(const TKey& key) const { return val; }
   TValue val;
};

template <typename... Args> struct MultiKeyHash;

template <typename TKey, typename... Args>
struct MultiKeyHash<TKey, Args...> : QHash<TKey, MultiKeyHash<Args...>>
{
   typedef TKey KeyType;
   typedef typename MultiKeyHash<Args...>::ValueType ValueType;
   typedef QHash<KeyType, MultiKeyHash<Args...>> QHashType;

   using QHashType::insert;
   using QHashType::value;

   MultiKeyHash() {}

   MultiKeyHash(const TKey &key, const Args&... args)
   {
      this->insert(key, MultiKeyHash<Args...>(args...));
   }

   void insert(const TKey &key, const Args&... args)
   {
      MultiKeyHash<Args...> val(args...);
      this->insert(key, val);
   }
   template <typename TKey1, typename ... Args1>
   const ValueType& value(const TKey1 &key1, const Args1&... args1) const
   {
      MultiKeyHash<Args...> const& val = this->value(key1);
      return val.value(args1...);
   }
};

template <typename TKey, typename TValue>
struct MultiKeyHash<TKey, TValue> : QHash<TKey, TValue> 
{
   typedef TKey KeyType;
   typedef TValue ValueType;
   typedef QHash<KeyType, ValueType> QHashType;

   MultiKeyHash() {}

   MultiKeyHash(const TKey &key, const TValue& val)
   {
      this->insert(key, val);
   }
};

void test1()
{
   MultiKeyHash<int, double> hash;
   hash.insert(10, 200.5);
   double v = hash.value(10);
   std::cout << "Value: " << v << std::endl;
}

void test3()
{
   MultiKeyHash<int, int, int, double> hash;
   hash.insert(10, 10, 10, 20.5);
   double v = hash.value(10, 10, 10);
   std::cout << "Value: " << v << std::endl;
}

int main()
{
   test1();
   test3();
   return 0;
};

运行程序的输出:

价值:200.5 价值:20.5

【讨论】:

  • 已接受的答案,用于提供带有附加 insert() 方法的完整解决方案。
【解决方案2】:

如果您将value 设为可变参数模板,则可以完全避免该问题,但代价是更糟糕的错误消息,因为转换将发生在函数内部而不是调用站点:

template <typename First, typename...Remainder>
const ValueType& value(First&& first, Remainder&&... rest) const {
    return value(std::forward<First>(first)).value(std::forward<Remainder>(rest)...);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-22
    • 2022-06-19
    • 2020-12-31
    • 1970-01-01
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多