简体   繁体   中英

Variadic default parameters

I wanted to program a multidimensional map the other day and stumbled over the following problem. Normally, for a map, you need a key , a cmp (or less ) and a hash -type. In a multidimensional map, you'd need one of those for each dimension of the map.

Now, how do you declare the map class? I tried the following:

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

For obvious reasons it didn't work so I came up with a workaround:

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;

While this works, it forces the user to repeat Dimension<...> all over the place, which is unfortunate if he just wanted to declare a simple map, say (int, int, int) -> float which would look like multimap<float, Dimension<int>, Dimension<int>, Dimension<int>> . What can I do to make this more pleasing to the user?

Note, with the declaration like above, it also makes it impossible to deduce the type of a specific Dimension from a potential constructor that takes a Comparator for each dimension.

How can I make the declaration easy to use so that eg

  • multimap<float, int, int, int> results in (int, int, int) -> float
  • mulitmap<float, Dimension<int, some_cmp_t, some_hash_t>, int> results in (int, int) -> float using a special comparator and hash function on dimension one.

Turn non-dimensions into dimensions by passing each type through a 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>;
};

Then whenever you are referring to a parameter pack of multimap , use:

typename DimensionFilter<Dimensions>::type...

DEMO

You can also make multimap an alias template, so that the actual type it refers to already receives only 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM