如何实现支持自定义键提取的C++自定义类型分组映射模板函数?
通用化vector元素按属性分组到map的实现
你需要多次将std::vector中的元素按特定属性分组存入std::map,比如以下两段重复逻辑的代码:
// 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 ); } }
解决方案:模板函数+Lambda表达式
可以通过模板函数+lambda表达式实现逻辑通用化,不需要让所有V类型继承基类。核心是给模板函数增加一个用于提取键值的函数对象参数,这个参数可以是lambda、函数指针或者仿函数。
同时可以简化原有的循环逻辑:利用std::map的operator[]特性——当键不存在时,会自动插入一个默认构造的std::vector<V>,省去手动调用find和insert的冗余代码。
完整模板函数实现
template<typename T, typename V, typename KeyExtractor> std::map<T, std::vector<V>> groupBy(const std::vector<V>& items, KeyExtractor keyExtractor) { std::map<T, std::vector<V>> groupedMap; for (const auto& item : items) { // 通过传入的keyExtractor获取当前元素的键值 T key = keyExtractor(item); // 直接用operator[]获取对应的vector,不存在则自动创建 groupedMap[key].push_back(item); } return groupedMap; }
调用示例
- 对应Sample A的调用:
// 用lambda传入getType()的调用逻辑 auto modesByType = groupBy(_modes, [](const Mode& mode) { return mode.getType(); });
- 对应Sample B的调用:
// 用lambda传入getTab()的调用逻辑 auto categoriesByTab = groupBy(_categories, [](const Category& category) { return category.getTab(); });
模板参数可以由编译器自动推导,无需显式指定,代码更简洁。
内容的提问来源于stack exchange,提问作者Marek Krzeminski
相关产品推荐
相关产品推荐

