|
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