这是我的一点贡献。
我们从存在方法开始:
template <unsigned>
static unsigned char exists_impl(...);
template <unsigned N, typename T>
static auto exists_impl(T const&&) ->
typename std::enable_if<sizeof(typename T::template D<N>),
unsigned char (&)[2]>::type;
template <typename T, unsigned N>
static constexpr bool exists() {
return sizeof(exists_impl<N>(std::declval<T>())) != 1;
}
我相信这里constexpr
和函数的使用确实在可读性方面带来了很多好处,所以我不使用典型的类型。
然后,我们使用典型的二分搜索(第二次尝试,见底部的第一次尝试),虽然失去了可读性,但为了从惰性实例化中受益,我们使用部分模板特化和std::conditional
:
template <typename T, unsigned low, unsigned high, typename = void>
struct highest_index_in;
template <typename T, unsigned low>
struct highest_index_in<T, low, low>: std::integral_constant<unsigned, low> {};
template <typename T, unsigned low, unsigned high>
struct highest_index_in<T, low, high, typename std::enable_if<(high == low + 1)>::type>:
std::integral_constant<unsigned, low + exists<T, low+1>()> {};
template <typename T, unsigned low, unsigned high>
struct highest_index_in<T, low, high, typename std::enable_if<(high > low + 1)>::type>:
std::conditional< exists<T, (low+high)/2>(),
highest_index_in<T, (low+high)/2, high>,
highest_index_in<T, low, (low+high)/2> >::type
{};
template <typename T>
static constexpr unsigned highest_index() {
return highest_index_in<T, 0, ~(0u)>::value;
} // highest_index
在liveworkspace演示,计算highest_index<C>()
几乎是瞬时的。
第一次尝试二进制搜索,不幸的是编译器需要递归地实例化函数体(以证明它们可以被实例化),因此它必须做的工作是巨大的:
template <typename T, unsigned low, unsigned high>
static constexpr auto highest_index_in() ->
typename std::enable_if<high >= low, unsigned>::type
{
return low == high ? low :
high == low + 1 ? (exists<T, high>() ? high : low) :
exists<T, (high + low)/2>() ? highest_index_in<T, (high+low)/2, high>() :
highest_index_in<T, low, (high+low)/2>();
} // highest_index_in
template <typename T>
static constexpr unsigned highest_index() {
return highest_index_in<T, 0, ~(0u)>();
} // highest_index
所以,不幸的是,highest_index
它不可用,并且clang很慢(并不是说gcc似乎做得更好)。