In my code I have a number of places where I need to take an std::vector of things and put it into a std::map indexed by something. For example here are two code snippets:
//sample A
std::map<Mode::Type, std::vector<Mode>> modesByType;
for( const auto& mode : _modes ) {
Mode::Type type = mode.getType();
auto it = modesByType.find( type );
if( it == modesByType.end() ) {
std::vector<Mode> v = { mode };
modesByType.insert( std::pair( type, v ) );
} else {
it->second.push_back( mode );
}
}
//sample B
std::map<unsigned, std::vector<Category>> categoriesByTab;
for( const auto& category : _categories ) {
unsigned tabIndex = category.getTab();
auto it = categoriesByTab.find( tabIndex );
if( it == categoriesByTab.end() ) {
std::vector<Category> v = { category };
categoriesByTab.insert( std::pair( tabIndex, v ) );
} else {
it->second.push_back( category );
}
}
I'd like to generalize this and create a template function like:
template<typename T, typename V>
std::map<T,std::vector<V>> getMapByType( const std::vector<V>& items, ?? ) {
std::map<T,std::vector<V>> itemsByType;
for( const auto& item : items ) {
unsigned index = ??;
auto it = itemsByType.find( index );
if( it == itemsByType.end() ) {
std::vector<V> v = { item };
itemsByType.insert( std::pair( index, v ) );
} else {
it->second.push_back( item );
}
}
return itemsByType;
}
My question is, how do I define the ?? argument to this function so that I can call the correct V.foo() function to get the index value for the map?
Note, I do not want to make all the classes that this template (V) accepts, inherit from a base class. Can I somehow specify a lambda argument?
have a pointer to a member fn as an extra parameter
template<typename T, typename V>
std::map<T,std::vector<V>> getMapByType( const std::vector<V>& items, T (V::*fn)()const) {
std::map<T,std::vector<V>> itemsByType;
for( const auto& item : items ) {
T index = (item.*fn)();
auto it = itemsByType.find( index );
if( it == itemsByType.end() ) {
std::vector<V> v = { item };
itemsByType.emplace( index, v );
} else {
it->second.push_back( item );
}
}
return itemsByType;
}
auto res = getMapByType(items, &Category::getTab);