可变参数默认参数

时间:2015-10-09 15:34:32

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

我想在前几天编写一个多维地图,偶然发现以下问题。通常,对于地图,您需要keycmp(或less)和hash类型。在多维地图中,您需要其中一个用于地图的每个维度。

现在,您如何声明地图类?我尝试了以下方法:

template<typename val, typename ... key, typename ... cmp, typename ... hash>
class multimap;

由于显而易见的原因它没有用,所以我想出了一个解决方法:

template<typename Key,
         typename Cmp = std::less<Key>,
         typename Hash = std::hash<Key>>
struct Dimension
{
  using Key = Key;
  using Cmp = Cmp;
  using Hash = Hash;
};
template<typename Val, typename ... Dimensions>
class multimap;
// Example usage:
multimap<float, Dimension<int>, Dimension<float, some_cmp_t>> my_map;

虽然这样做有效,但它会强制用户在整个地方重复Dimension<...>,如果他只想宣布一张简单的地图,那就不幸了!(int, int, int) -> float看起来像multimap<float, Dimension<int>, Dimension<int>, Dimension<int>> }。我该怎么做才能让用户更满意?

注意,使用上面的声明,它也使得无法从为每个维度获取Comparator的潜在构造函数推断出特定Dimension的类型。

如何使声明易于使用,例如

  • multimap<float, int, int, int>会产生(int, int, int) -> float
  • mulitmap<float, Dimension<int, some_cmp_t, some_hash_t>, int>会导致(int, int) -> float在第一维上使用特殊的比较器和哈希函数。

1 个答案:

答案 0 :(得分:3)

通过将每个类型传递给辅助特征来将非维度转换为维度:

template <typename T>
struct DimensionFilter
{
    using type = Dimension<T>;
};

template <typename Key, typename Cmp, typename Hash>
struct DimensionFilter<Dimension<Key, Cmp, Hash>>
{
    using type = Dimension<Key, Cmp, Hash>;
};

然后,无论何时引用multimap的参数包,请使用:

typename DimensionFilter<Dimensions>::type...

DEMO

您还可以将multimap设为别名模板,以便其引用的实际类型仅接收Dimensions

namespace detail
{
    template <typename Val, typename ... Dimensions>
    struct multimap {};
}

template <typename Val, typename ... Dimensions>
using multimap = detail::multimap<Val, typename DimensionFilter<Dimensions>::type...>;

DEMO 2