Boost logo

Boost Users :

From: Joaquin M López Muñoz (joaquinlopezmunoz_at_[hidden])
Date: 2019-11-20 17:57:53


El 20/11/2019 a las 14:12, Christophe B via Boost-users escribió:
> Hi,
>
> I have currently
>
> template <typename Key, typename Value>
> std::vector<Key> keys(const std::map<Key, Value> &m) { ... }
>
> I'd like to write an overload that works also with the indices
> interface of multi_index_container.
>
> [...]
>
> template< typename Tag,typename Value,typename
> IndexSpecifierList,typename Allocator >
> auto keys(const typename multi_index::index<
> multi_index::multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type&
> m)
> {
>     typedef decltype(c.key_extractor()(*c.begin())) key_type; // A
> better definition would be welcome
>     std::vector<key_type> result;
>     result.reserve(c.size());
>     for (const auto &elem : c) {
>         result.push_back(c.key_extractor()(elem));
>     }
>     return result;
> }
>
> But the overload resolution fails.

The second overload is not picked up because Tag, Value, etc. are being
used in a nondeduced context:

https://stackoverflow.com/questions/1268504/why-is-the-template-argument-deduction-not-working-here

So, this approach won't get you anywhere. You have two options:

1. You can use the name of the actual class implementing ordered indices:

 Â Â Â  template<typename... Args>
 Â Â Â  auto keys(const boost::multi_index::detail::ordered_index<Args...>&
c){...}

THIS IS STRONGLY DISCOURAGED, because this name is not documented.
Basically, you're relying on
an implementation detail. Rather use:

2. With SFINAE and a little ingenuity you can have something like:

 Â Â Â  template<
 Â Â Â Â Â  typename Index,
 Â Â Â Â Â  std::enable_if_t<
 Â Â Â Â Â Â Â  sizeof(typename Index::key_type)&&
 Â Â Â Â Â Â Â  sizeof(std::declval<const Index>().key_extractor())
 Â Â Â Â Â  >* =nullptr
 Â Â Â  >
 Â Â Â  auto keys(const Index& c)
 Â Â Â  {
 Â Â Â Â Â  using key_type=typename Index::key_type;
 Â Â Â Â Â  std::vector<key_type> result;
 Â Â Â Â Â  result.reserve(c.size());
 Â Â Â Â Â  for(const auto &elem:c){
 Â Â Â Â Â Â Â  result.push_back(c.key_extractor()(elem));
 Â Â Â Â Â  }
 Â Â Â Â Â  return result;
 Â Â Â  }

Here, we're using SFINAE to activate the overload *only* when Index does
have a nested
key_type type and a key_extractor member function, which can be taken as
a very certain
bet that we're indeed dealing with a key-based Boost.MultiIndex index.
This is, if you wish,
poor man's pre-C++20 concepts. BTW, this overloads also picks hashed and
ranked indices.

Best,

Joaquín M López Muñoz


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net