如何在C++11中使用万能引用合并两个map_at函数?
用C++11万能引用合并两个map_at函数的解决方案
问题背景
需要将处理const和非const容器的两个map_at函数,通过C++11的万能引用T&&合并为单一模板函数。原代码如下:
#include <map> #include <exception> template<typename T> // const版本 const typename T::mapped_type& map_at(const T& m, const typename T::key_type& key) { if (const auto& iter = m.find(key); iter != m.cend()) { return iter->second; } else { throw std::exception("blah"); } } template<typename T> // 非const版本 typename T::mapped_type& map_at(T& m, const typename T::key_type& key) { if (const auto& iter = m.find(key); iter != m.cend()) { return iter->second; } else { throw std::exception("blah"); } } int main() { using T = std::map<int, float>; T t; const T ct; try { map_at(ct, 3); // 调用const版本 } catch (...){} try { map_at(t, 3); // 调用非const版本 } catch (...){} }
尝试使用万能引用的版本出现编译错误:
1> ConsoleApplication1.cpp(557,9): error C2672: 'map_at': no matching overloaded function found
错误版本代码:
template<typename T> // T&&版本 typename T::mapped_type&& map_at(T&& m, const typename T::key_type& key) { if (const auto& iter = m.find(key); iter != m.cend()) { return iter->second; } else { throw std::exception("blah"); } }
错误原因分析
- 返回值类型错误:当传入const左值容器时,
T会被推导为const std::map<int, float>&,此时typename T::mapped_type&&是右值引用,但容器中元素的类型是const float&,无法绑定到右值引用,导致类型不匹配。 - key类型推导错误:当
T是引用类型时,T::key_type会编译失败——引用类型没有嵌套的key_type,必须先移除引用,获取原始容器类型的嵌套类型。
正确实现(C++11兼容)
利用C++11的类型萃取工具std::remove_reference和std::conditional,推导正确的返回值类型,并修正key的参数类型:
#include <map> #include <stdexcept> #include <type_traits> template<typename T> auto map_at(T&& m, const typename std::remove_reference<T>::type::key_type& key) -> typename std::conditional< std::is_const<typename std::remove_reference<T>::type>::value, const typename std::remove_reference<T>::type::mapped_type&, typename std::remove_reference<T>::type::mapped_type& >::type { auto iter = m.find(key); if (iter != m.cend()) { return iter->second; } throw std::runtime_error("Key not found in map"); } int main() { using Map = std::map<int, float>; Map mutable_map; const Map const_map; try { // 获取const引用,对应原const版本 const float& val1 = map_at(const_map, 3); } catch (const std::exception&) {} try { // 获取非const引用,对应原非const版本 float& val2 = map_at(mutable_map, 3); } catch (const std::exception&) {} }
代码说明
std::remove_reference<T>::type:移除T的引用属性,获取原始容器类型(比如const std::map<int, float>或std::map<int, float>)。std::conditional:根据原始容器是否为const类型,选择返回const mapped_type&或mapped_type&,完美匹配原两个版本的返回值语义。- 参数
key的类型改为const typename std::remove_reference<T>::type::key_type&,确保无论T是引用还是值类型,都能正确获取容器的key类型。
内容的提问来源于stack exchange,提问作者user9636586
相关产品推荐
相关产品推荐

