如何在对数(至少以二为底)的编译时间内(严格来说,以对数的实例化数量)定义集合的奇数?
我目前能做的是在线性时间内达到期望:
#include <type_traits>
#include <utility>
struct filler { template< typename type > operator type (); };
template< typename A, typename index_sequence = std::index_sequence<>, typename = void >
struct aggregate_arity
: index_sequence
{
};
template< typename A, std::size_t ...indices >
struct aggregate_arity< A, std::index_sequence< indices... >, std::__void_t< decltype(A{(indices, std::declval< filler >())..., std::declval< filler >()}) > >
: aggregate_arity< A, std::index_sequence< indices..., sizeof...(indices) > >
{
};
struct A0 {};
struct A1 { double x; };
struct A2 { int i; char c; };
struct C50 { template< typename ...Args, typename = std::enable_if_t< (sizeof...(Args) < 51) > > C50(Args &&...) { ; } };
static_assert(aggregate_arity< A0 >::size() == 0);
static_assert(aggregate_arity< A1 >::size() == 1);
static_assert(aggregate_arity< A2 >::size() == 2);
static_assert(aggregate_arity< C50 >::size() == 50);
Live example。
如果“arity”一词不佳,请指正。
我认为原则上是可能的:首先,需要从一次开始直到SFINAE失败(一定是软性方式)对两次审理进行两次加倍,然后再使用等分法。
最佳答案
讨论区
(讨论基于我的另一个答案,我现在将其删除。)
与原始问题一样,以下答案检查是否可以使用给定数量的参数来调用聚合的构造函数。对于聚合,可以通过使用标准中的以下属性在此模式下进行二进制搜索:
和
但是,正如您已经在问题标题中所隐含的那样,二进制搜索通常不适用于非聚合,首先是由于这样的事实,即通常无法使用比必要数量更少的参数来调用非聚合,其次是由于非聚合聚合可以具有explicit
构造函数,因此通过struct filler
进行的“转换为任何东西”的技巧将不起作用。
实作
第一个成分是来自here的is_callable
检查:
template<typename V, typename ... Args>
struct is_constructible_impl
{
template<typename C> static constexpr auto test(int) -> decltype(C{std::declval<Args>() ...}, bool{}) { return true; }
template<typename> static constexpr auto test(...) { return false; }
static constexpr bool value = test<V>(int{});
using type = std::integral_constant<bool, value>;
};
template<typename ... Args>
using is_constructible = typename is_callable_impl<Args...>::type;
请注意,此参数还可以使用少于必需数量的参数(与您的检查不同)。
接下来,一个帮助函数,该函数接受一个整数参数,并返回该聚集是否可通过相应数量的构造函数参数调用:
template<typename A, size_t ... I>
constexpr auto check_impl(std::index_sequence<I ...>)
{
return is_constructible<A, decltype(I, filler{}) ...>::value;
}
template<typename A, size_t N>
constexpr auto check()
{
return check_impl<A>(std::make_index_sequence<N>{});
}
最后是二进制搜索:
template<typename A, size_t Low, size_t Up, size_t i = Low + (Up - Low)/2>
struct binary_search
: public std::conditional_t<check<A, i>() && !check<A,i+1>()
, std::integral_constant<size_t, i>
, std::conditional_t<check<A, i>()
, binary_search<A, i, Up>
, binary_search<A, Low, i> >
>
{};
用作
int main()
{
static_assert(binary_search<A2,0,10>::value==2);
}