std::remove_all_extents为何需3个模板声明?2个似可满足需求
关于libcpp中std::remove_all_extents模板特化的疑问
先看libcpp中std::remove_all_extents的源码实现:
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS remove_all_extents {typedef _Tp type;}; template <class _Tp> struct _LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[]> {typedef typename remove_all_extents<_Tp>::type type;}; template <class _Tp, size_t _Np> struct _LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[_Np]> {typedef typename remove_all_extents<_Tp>::type type;};
我认为仅第一个和最后一个声明即可实现该递归模板的功能,且自行尝试仅用2个声明也达成了相同效果,想请教为何需要中间针对_Tp[]的模板特化声明?
解答
核心原因是处理未知大小的数组类型。
你测试时可能只用到了固定大小的数组(比如int[5]),这种情况下最后一个带size_t _Np的特化确实能递归处理:固定大小数组匹配该特化,然后递归到_Tp,直到剥离所有数组维度。
但如果遇到未知大小的数组类型(比如函数参数里的int[],或是推导得到的不完整数组类型),带size_t _Np的特化就匹配不上了——因为未知大小的数组没有编译期确定的_Np参数。这时候中间针对_Tp[]的特化就会生效,它专门处理这类“不完整数组类型”,继续递归剥离外层数组维度,直到得到基础类型。
举个实际场景的例子:
// 定义一个未知大小的数组类型 using UnboundedArr = int[]; // 剥离所有数组维度,得到基础类型int using BaseType = std::remove_all_extents<UnboundedArr>::type;
如果没有中间这个特化,上面的代码会直接匹配主模板,返回的BaseType还是int[],完全达不到剥离数组维度的目的。
另外从C++标准的要求来看,std::remove_all_extents需要支持所有合法的数组类型,包括未知大小的数组,所以必须添加这个特化来覆盖这类场景。
内容的提问来源于stack exchange,提问作者Mike Reznikov
相关产品推荐
相关产品推荐

