如何在对数(至少以二为底)的编译时间内(严格来说,以对数的实例化数量)定义集合的奇数?

我目前能做的是在线性时间内达到期望:

#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进行的“转换为任何东西”的技巧将不起作用。

实作

第一个成分是来自hereis_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);
}

09-27 14:55