【问题标题】:Filling an array on compiletime under some predicate在某些谓词下在编译时填充数组
【发布时间】:2015-07-20 12:30:11
【问题描述】:

有没有办法制作一个无符号整数的constexpr-Array 来满足 constexpr 布尔函数 pred(std::size_t) 给出的某些谓词?

我尝试了很多,尤其是indices trick,只是为了发现我的数据太大,以至于超过了递归模板实例化限制256。我将无法更改此限制,如果可能的话,可以改变它。

正如 cmets 中所要求的,这是我想要实现的一些伪代码:

template<std::size_t... Is> 
struct Sequence{};

template<std::size_t N, std::size_t... Is> 
struct SequenceGenerator : SequenceGenerator<N-1, N-1, Is...>
{}; //obviously here it gets too deep into recursion, as mentioned

template<std::size_t... Is> 
struct SequenceGenerator<0, Is...> : Sequence<Is...>
{};

template<std::size_t N>
struct MyData
{
    std::size_t values[N];

    static constexpr std::size_t size()
    { return N; }
};

template<typename Lambda, std::size_t... Is> 
constexpr MyData<sizeof...(Is)> MyGen(Sequence<Is...>, Lambda func)
{
    if(func(Is)...)
        return {{ Is... }};
    else
        return /*some not-invalidating but current element discarding thing*/
}

template<std::size_t N, typename Lambda>
constexpr Generator<N> MyGen(Lambda func)
{
    return MyGen(SequenceGenerator<N>(), func);
}

constexpr bool pred(std::size_t i) noexcept
{
    //some condition making up a "range"
    return i < 360ULL && i > 2ULL;
}

【问题讨论】:

  • 你能告诉我们一些你想要实现的(伪)代码吗?也许使用不超过限制但其他工作的小型数据集并向我们展示您的意思?
  • @DanielFrey 添加了代码
  • 那么您的想法是通过给定谓词“过滤”范围吗?此外,如果您正在寻找高效的“序列生成器”,我编写了一个库,提供one with logarithmic instantiation depth
  • @Columbo 是的,但是范围大于 256,显然必须在编译时。

标签: c++ c++11 variadic-templates template-meta-programming compile-time


【解决方案1】:

我能想出的唯一解决方案是使用一个生成器来生成这两个序列

  • O(log N)
  • 过滤同时生成序列

也就是说,我开始 with this O(log N) generator 并将谓词从 constexpr 函数更改为更方便的 std::integral_constant - 我希望你可以接受。结果是这样的:

#include <utility>
#include <iostream>
#include <type_traits>

template<std::size_t...> struct seq{ using type = seq; };

template<class S1, class S2> struct concat;

template<std::size_t... I1, std::size_t... I2>
struct concat<seq<I1...>, seq<I2...>>
  : seq<I1..., I2...>{};

template<template<std::size_t> class pred, std::size_t B, std::size_t N>
struct gen_seq : concat<typename gen_seq<pred, B, N/2>::type, typename gen_seq<pred, B + N/2, N - N/2>::type>::type {};

template<template<std::size_t> class pred, std::size_t B> struct gen_seq<pred, B, 0> : seq<> {};
template<template<std::size_t> class pred, std::size_t B> struct gen_seq<pred, B, 1> : std::conditional<pred<B>::value,seq<B>,seq<>>::type {};

template<std::size_t N>
struct MyData
{
    std::size_t values[N];

    static constexpr std::size_t size()
    { return N; }
};

template<std::size_t... Is>
constexpr MyData<sizeof...(Is)> MyGen(seq<Is...>)
{
    return {{ Is... }};
}

template<template<std::size_t> class pred, std::size_t N>
constexpr auto MyGen() -> decltype(MyGen(typename gen_seq<pred,0,N>::type()))
{
    return MyGen(gen_seq<pred,0,N>());
}

template< std::size_t N > struct my_pred : std::integral_constant< bool, N % 3 == 0 > {};

int main()
{
    auto data = MyGen<my_pred, 10>();
    static_assert( data.size() == 4, "Oops" );

    for ( auto i : data.values )
       std::cout << i << std::endl;

    auto data2 = MyGen<my_pred, 10000>();
    static_assert( data2.size() == 3334, "Oops" );
}

Live example

正如您在现场示例中所见,即使是 10000 个作品 :)

使用constexpr bool pred(std::size_t) 的版本不是那么方便(您不能只是“调用”该方法,您需要为每个pred 编写更多代码),但这也是可能的。

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 1970-01-01
    • 2011-08-22
    相关资源
    最近更新 更多