In fmt/core.h
, I noticed the function count_named_args()
which uses the template function count
with a given predicate.
And I found the overloaded version for count
version is weird:
template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t {
return (B1 ? 1 : 0) + count<B2, Tail...>();
}
why do we need to take a template parameter bool B2
to extract the next boolean value explicitly, and not the parameter pack bool... Tail
directly?
If I remove the bool B2
stuff, and try compile:
template <bool B1, bool... Tail> constexpr auto count() -> size_t {
return (B1 ? 1 : 0) + count<Tail...>();
}
static_assert(count<false>() == 0);
static_assert(count<true, false>() == 1);
It gives an error as it is ambiguous to determine the overload when the parameter number reduces to the last one:
size_t count<false,>(void) noexcept
size_t count<false>(void) noexcept
Looking at the current main, there are two function templates:
template <bool B = false> constexpr auto count() -> size_t { return B ? 1 : 0; }
template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t {
return (B1 ? 1 : 0) + count<B2, Tail...>();
}
If those were instead
template <bool B = false> constexpr auto count() -> size_t { return B ? 1 : 0; }
template <bool B1, bool... Tail> constexpr auto count() -> size_t {
return (B1 ? 1 : 0) + count<Tail...>();
}
then for call count<false>()
, both candidates are considered and as per overload resolution rules neither is more specialized than the other -> ambiguity. Remember, parameter packs can be empty. Why is having an extra parameter pack not considered less specialized, that I honestly do not know.
Only having <bool B1, bool... Tail>
would not work for zero arguments and having extra non-template count
for this case would not work for corner cases of count<pack...>()
and pack
being empty. On the other hand <bool B = false>
can still be called like count()
thanks to the default value.
I think <bool B = false>
and <bool B1, bool B2, bool... Tail>
is the most generic and simplest solution.