为何fmt/core.h中count()函数重载要显式声明B2模板参数?
解析fmt库count模板函数显式提取B2参数的原因
在fmt/core.h中,count_named_args()函数会用到一个带谓词的count模板函数,它的重载写法比较特殊:
template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t { return (B1 ? 1 : 0) + count<B2, Tail...>(); }
很多开发者会疑惑:为什么要显式提取下一个布尔值作为模板参数B2,而不是直接用参数包bool... Tail?
移除B2后的编译问题
如果修改实现,去掉B2相关代码:
template <bool B1, bool... Tail> constexpr auto count() -> size_t { return (B1 ? 1 : 0) + count<Tail...>(); }
搭配用于终止递归的空参数包基础重载:
template <> constexpr auto count() -> size_t { return 0; }
执行以下断言时:
static_assert(count<false>() == 0); static_assert(count<true, false>() == 1);
会触发编译错误,核心问题是参数数量减少到最后一个时,重载判定出现歧义:
size_t count<false,>(void) noexcept size_t count<false>(void) noexcept
为什么需要显式提取B2
这个写法的核心目的是避免递归终止阶段的重载歧义:
- 原模板要求至少传入2个布尔模板参数,递归过程中,每次调用
count<B2, Tail...>()会逐步减少参数数量,直到只剩1个参数,此时会匹配专门处理单个布尔参数的重载(比如template <bool B> constexpr auto count() -> size_t { return B ? 1 : 0; }),再由这个单个参数版本调用空参数的终止重载。 - 如果去掉
B2,模板只要求至少1个参数,当调用count<false>()时,编译器无法确定应该匹配template <bool B1, bool... Tail>(此时Tail为空)还是空参数的基础重载,从而产生歧义。
通过显式提取B2,强制模板必须接收至少2个参数,把单个参数的情况分离到单独的重载中,彻底避免了递归末尾的匹配冲突。
内容的提问来源于stack exchange,提问作者Honey.W
相关产品推荐
相关产品推荐

