可变参数默认参数

Variadic default parameters

前几天我想编写一个多维地图,无意中遇到了以下问题。通常,对于地图,您需要 keycmp(或 less)和 hash 类型。在多维地图中,地图的每个维度都需要一个。

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

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>>。我该怎么做才能让用户更满意?

请注意,使用上面的声明,也无法从为每个维度采用比较器的潜在构造函数中推断出特定维度的类型。

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

通过辅助特征传递每种类型,将非维度转换为维度:

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