4

是否有辦法使constexpr - 無符號整數的數組滿足由constexpr布爾函數pred(std::size_t)給出的謂詞?根據某個謂詞在編譯時填充數組

我嘗試了很多,特別是indices trick,只是爲了發現我的數據太大,因此它超出了256的遞歸模板實例化限制。我將無法更改此限制,如果它有可能改變它。

由於要求在評論,這裏是我想達到什麼樣的一些僞代碼:

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; 
} 
+1

你能告訴我們一些你想達到的(僞)代碼嗎?也許有一個小數據集沒有超出限制,但在其他方面的工作,並告訴我們你的意思? –

+0

@DanielFrey添加的代碼 – NaCl

+0

那麼你的想法是用給定的謂詞「過濾」一個範圍?另外,如果你正在尋找一個高效的「序列生成器」,我寫了一個庫,提供[對數實例化深度](https://github.com/Arcoth/VTMPL/blob/master/index_list.hxx)。 – Columbo

回答

5

唯一的解決辦法我能想出是使用一個發電機這既是

序列
  • 爲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寫更多的代碼),但也有可能。