可变的默认参数

Variadic default parameters

本文关键字:参数 默认      更新时间:2023-10-16

前几天我想编写一个多维映射程序,遇到了以下问题。通常,对于映射,您需要key, cmp(或less)和hash类型。在多维映射中,每个维度都需要一个。

现在,如何声明map类呢?我尝试了以下操作:

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的潜在构造函数中推断出特定维度的类型。

如何使声明易于使用,以便

  • multimap<float, int, int, int>导致(int, int, int) -> float
  • mulitmap<float, Dimension<int, some_cmp_t, some_hash_t>, int>使用一个特殊的比较器和哈希函数在维度1上得到(int, int) -> float

通过helper trait传递每种类型,将非维度转换为维度:

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...

您还可以使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...>;

演示2