const指针与模板配合使用时的编译错误问题排查
编译错误原因分析
问题代码
#include <memory> #include <iostream> #include <map> template <typename MapT> inline typename MapT::mapped_type * find_element(MapT &m, const typename MapT::key_type &key) { auto it = m.find(key); return it != m.end() ? &it->second : NULL; } int main() { std::map<std::string, double> map0; const std::map<std::string, double> map1 = map0; auto d1 = find_element(map1, "test"); std::cout << d1 << "\n"; }
编译报错信息
const.cc: In instantiation of ‘typename MapT::mapped_type* find_element(MapT&, const typename MapT::key_type&) [with MapT = const std::map<std::__cxx11::basic_string<char>, double>; typename MapT::mapped_type = double; typename MapT::key_type = std::__cxx11::basic_string<char>]: const.cc:15:38: required from here const.cc:9:24: error: invalid conversion from ‘const double*’ to ‘std::map<std::__cxx11::basic_string<char>, double>::mapped_type*’ {aka ‘double*’} [-fpermissive] 9 | return it != m.end() ? &it->second : NULL; | ^ | | | const double*
错误原因
当传入const修饰的std::map(即代码中的map1)时,模板参数MapT被推导为const std::map<std::string, double>:
- 虽然
MapT::mapped_type仍是double,但const容器的迭代器是const_iterator,其指向的元素为const double类型。 - 取
it->second的地址得到const double*,但函数声明的返回值是double*(即MapT::mapped_type*)。 - C++禁止
const T*隐式转换为T*,因为这会破坏const的只读语义——原本不可修改的元素,通过非const指针就能被修改,违反了const的设计初衷。
修复方案
方案1:使用C++14及以上的自动返回类型推导
让编译器根据容器的const属性自动推导返回值类型,非const容器返回非const指针,const容器返回const指针:
#include <memory> #include <iostream> #include <map> template <typename MapT> inline auto find_element(MapT &m, const typename MapT::key_type &key) { auto it = m.find(key); return it != m.end() ? &it->second : nullptr; // 推荐用nullptr代替NULL } int main() { std::map<std::string, double> map0; const std::map<std::string, double> map1 = map0; auto d1 = find_element(map1, "test"); // d1为const double*类型 auto d2 = find_element(map0, "test"); // d2为double*类型 std::cout << d1 << "\n"; }
方案2:提供两个重载版本
分别为非const容器和const容器编写函数重载,明确返回对应的指针类型:
#include <memory> #include <iostream> #include <map> // 非const容器版本:返回非const指针 template <typename MapT> inline typename MapT::mapped_type* find_element(MapT &m, const typename MapT::key_type &key) { auto it = m.find(key); return it != m.end() ? &it->second : nullptr; } // const容器版本:返回const指针 template <typename MapT> inline const typename MapT::mapped_type* find_element(const MapT &m, const typename MapT::key_type &key) { auto it = m.find(key); return it != m.end() ? &it->second : nullptr; } int main() { std::map<std::string, double> map0; const std::map<std::string, double> map1 = map0; auto d1 = find_element(map1, "test"); // const double*类型 auto d2 = find_element(map0, "test"); // double*类型 std::cout << d1 << "\n"; }
内容的提问来源于stack exchange,提问作者MK.
相关产品推荐
相关产品推荐

