将basic_string.h移至自定义命名空间编译出错,为何std中可单模板参数使用?
我正在研究basic_string.h的实现,尝试将其放到自己的独立命名空间中编译,但用GCC 12.1编译器时出现了编译错误,错误信息如下:
basic_string.h: error: wrong number of template arguments (1, should be 3)
operator==(const basic_string<_CharT>& __lhs,
basic_string类的模板定义包含3个参数:
// 21.3 Template class basic_string template <typename _CharT, typename _Traits, typename _Alloc> class basic_string { typedef typename _Alloc::template rebind<_CharT>::other _CharT_alloc_type; };
但后续的operator==重载中,使用了仅含1个模板参数的basic_string<_CharT>:
template <typename _CharT> inline typename __gnu_cxx::__enable_if<std::__is_char<_CharT>::__value, bool>::__type operator==(const basic_string<_CharT>& __lhs, const basic_string<_CharT>& __rhs) _GLIBCXX_NOEXCEPT { return (__lhs.size() == __rhs.size() && !std::char_traits<_CharT>::compare(__lhs.data(), __rhs.data(), __lhs.size())); }
为什么这段代码在std命名空间中能正常编译,放到我自己的命名空间里就报错?
核心原因是标准库中的std::basic_string带有默认模板参数,而你复制到自己命名空间的basic_string没有添加这些默认参数。
在C++标准中,std::basic_string的完整定义包含默认参数:
template<class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>> class basic_string;
当你只写std::basic_string<_CharT>时,编译器会自动补全后面两个默认参数,等价于std::basic_string<_CharT, std::char_traits<_CharT>, std::allocator<_CharT>>。
但你自己命名空间里的basic_string模板只声明了3个参数,没有指定默认值,编译器无法推断缺失的_Traits和_Alloc参数,因此会报“模板参数数量不匹配”的错误。
解决方法很简单:给你自己命名空间中的basic_string添加对应的默认模板参数,和标准库的定义保持一致:
template <typename _CharT, typename _Traits = std::char_traits<_CharT>, typename _Alloc = std::allocator<_CharT>> class basic_string { typedef typename _Alloc::template rebind<_CharT>::other _CharT_alloc_type; };
这样basic_string<_CharT>的写法就能被编译器正确解析,编译错误也就消失了。
内容的提问来源于stack exchange,提问作者Ruster

