问题
I have a template class(CrMultiIndex) that receive as template parameter a definition of boost multi index(GlobalHash).
I need :
- To add statistics to my template class according to Index used. So i need a way to resize the vector(m_StatsByIndex) at init with the number of existing indices.
- I still want the user to search according to tag and not index number. So i need a way to convert from tag to index number so i can update statistics in vector according to index in vector.
I have template class
template <typename KeysType, typename MultiIndexType>
class CrMultiIndex
{
std::vector<SrStatisticsByIndex> m_StatsByIndex;
public:
MultiIndexType *m_pMultiIndex=NULL;
CrMultiIndex()
{
m_pMultiIndex = new MultiIndexType(typename
MultiIndexType::ctor_args_list());
}
Here is the definition of boost multi index container:
typedef boost::multi_index::multi_index_container<
CrUsersKeys,
UsersKey_hash_indices/*,
bip::allocator<CrUsersKeys,bip::managed_shared_memory::segment_manager>*/
> GlobalHash;
with a search function according to Tag
template <typename TagType,typename SearchingKey>
typename MultiIndexType::template index<TagType>::type::iterator
GetIteratorBy(SearchingKey & key)
{
return m_pMultiIndex->template get<TagType>().find(key) ;
}
Code is at http://coliru.stacked-crooked.com/a/d97195a6e4bb7ad4
回答1:
As a supplement to sehe's answer, this a rewrite of IndexOfTag
that does not depend on undocumented Boost.MultiIndex features:
Live On Coliru
template<typename MultiIndexContainer,std::size_t N=0>
struct index_position:index_position<MultiIndexContainer,N+1>
{
using index_type=typename boost::multi_index::nth_index<MultiIndexContainer,N>::type;
using index_position<MultiIndexContainer,N+1>::case_of;
static constexpr std::size_t case_of(std::in_place_type_t<index_type>){return N;}
};
template<typename MultiIndexContainer>
struct index_position<
MultiIndexContainer,
boost::mpl::size<typename MultiIndexContainer::index_type_list>::value
>
{
static constexpr void case_of(...){}
};
template <typename MultiIndexContainer,typename Tag>
constexpr std::size_t IndexOfTag()
{
using index_type=typename boost::multi_index::index<MultiIndexContainer,Tag>::type;
return index_position<MultiIndexContainer>::case_of(std::in_place_type<index_type>);
}
Edit: In C++14:
Live On Coliru
template<typename MultiIndexContainer,std::size_t N=0>
struct index_position:index_position<MultiIndexContainer,N+1>
{
using index_type=typename boost::multi_index::nth_index<MultiIndexContainer,N>::type;
using index_position<MultiIndexContainer,N+1>::case_of;
static constexpr std::size_t case_of(index_type*){return N;}
};
template<typename MultiIndexContainer>
struct index_position<
MultiIndexContainer,
boost::mpl::size<typename MultiIndexContainer::index_type_list>::value
>
{
static constexpr void case_of(...){}
};
template <typename MultiIndexContainer,typename Tag>
constexpr std::size_t IndexOfTag()
{
using index_type=typename boost::multi_index::index<MultiIndexContainer,Tag>::type;
return index_position<MultiIndexContainer>::case_of((index_type*)(nullptr));
}
回答2:
You'd need to query the embedded index type lists:
typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;
template <typename Tag> constexpr static size_t IndexOfTag() {
namespace mpl = boost::mpl;
using tl = typename MultiIndexType::index_type_list;
using B = typename mpl::begin<tl>::type;
using helper = typename MultiIndexType::template index<Tag>;
static_assert(helper::index_found, "index not found");
auto N = mpl::distance<B, typename helper::iter>::value;
return N;
}
Or, using Boost Mpl all the way:
typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;
template <typename Tag> constexpr static size_t IndexOfTag() {
namespace mpl = boost::mpl;
using tl = typename MultiIndexType::index_type_list;
using B = typename mpl::begin<tl>::type;
using E = typename mpl::end<tl>::type;
using It = typename mpl::find_if<tl, bmi::detail::has_tag<Tag> >::type;
static_assert(not std::is_same<E, It>(), "index not found");
auto N = mpl::distance<B, It>::value;
return N;
}
You can use it like so:
template <typename TagType, typename SearchingKey>
typename MultiIndexType::template index<TagType>::type::iterator
GetIteratorBy(SearchingKey &key) {
auto& idx = m_pMultiIndex.template get<TagType>();
auto& stats = GetStats<TagType>();
auto it = idx.find(key);
++(it == idx.end()? stats.searchedNotFound : stats.searchedSuccessfully);
return it;
}
DEMO
Note the code has been simplified:
Live On Coliru
#include <iostream>
#include <boost/multi_index/member.hpp> // for member
#include <boost/multi_index/hashed_index.hpp> // for hashed_unique
#include <boost/multi_index/ordered_index.hpp> // for ordered_non_unique
#include <boost/multi_index_container.hpp> // for multi_index_container
namespace bmi = boost::multi_index;
struct SrStatisticsByIndex {
int deleted;
int searchedSuccessfully;
int searchedNotFound;
};
template <typename MultiIndexType, typename ValueType = typename MultiIndexType::value_type>
class CrMultiIndex {
typedef typename MultiIndexType::index_type_list::size NumberOfIndexes;
template <typename Tag> constexpr static size_t IndexOfTag() {
using tl = typename MultiIndexType::index_type_list;
using B = typename boost::mpl::begin<tl>::type;
using helper = typename MultiIndexType::template index<Tag>;
static_assert(helper::index_found, "index not found");
return boost::mpl::distance<B, typename helper::iter>::value;
}
public:
MultiIndexType m_pMultiIndex;
template <typename Tag> SrStatisticsByIndex& GetStats()
{ return m_StatsByIndex.at(IndexOfTag<Tag>()); }
template <typename Tag> SrStatisticsByIndex const& GetStats() const
{ return m_StatsByIndex.at(IndexOfTag<Tag>()); }
// All the protected function are non locking function
template <typename TagType, typename SearchingKey>
typename MultiIndexType::template index<TagType>::type::iterator
GetIteratorBy(SearchingKey &key) {
auto& idx = m_pMultiIndex.template get<TagType>();
auto& stats = GetStats<TagType>();
auto it = idx.find(key);
++(it == idx.end()? stats.searchedNotFound : stats.searchedSuccessfully);
return it;
}
void Insert(ValueType const &key) {
std::cout << (m_pMultiIndex.insert(key).second? "success":"failed") << std::endl;
}
private:
std::vector<SrStatisticsByIndex> m_StatsByIndex { NumberOfIndexes() };
};
class CrUsersValue {
int val1;
int val2;
};
class CrUsersKeys {
public:
int IMSI;
int TIMESTAMP;
CrUsersValue val;
};
typedef boost::multi_index::multi_index_container<
CrUsersKeys,
bmi::indexed_by<
bmi::ordered_non_unique<bmi::tag<struct TIMESTAMP_tag>,
bmi::member<CrUsersKeys, int, &CrUsersKeys::TIMESTAMP> >,
bmi::hashed_unique<bmi::tag<struct IMSI_tag>,
bmi::member<CrUsersKeys, int, &CrUsersKeys::IMSI> /*, boost::hash<int>, std::equal_to<int>*/>
>
/*, bip::allocator<CrUsersKeys,bip::managed_shared_memory::segment_manager>*/
>
GlobalHash;
int main() {
CrMultiIndex<GlobalHash> multi;
CrUsersKeys key;
key.IMSI = 2;
multi.Insert(key);
int searchKey = 2;
auto it = multi.GetIteratorBy<IMSI_tag>(searchKey);
if (it != multi.m_pMultiIndex.get<IMSI_tag>().end())
std::cout << "found " << std::endl;
}
Prints
success
found
来源:https://stackoverflow.com/questions/49232257/find-boost-multi-index-tag-to-index-and-number-of-indices