C++ constexpr : Compute a std array at compile time

后端 未结 2 2103
失恋的感觉
失恋的感觉 2021-02-08 20:41

I want to convert an \"array\" of bool to a integer sequence. So I need to compute an std::array at compile time.

Here is my code



        
相关标签:
2条回答
  • 2021-02-08 20:55

    Is it possible to do otherwise?

    About correctness answered JVApen (+1).

    A possible alternative is avoid std::array at all and construct the index sequence in a recursive way using template specialization

    The following is a full compilable example

    #include <utility>
    #include <type_traits>
    
    template <typename, std::size_t, bool...>
    struct bar;
    
    // true case
    template <std::size_t ... Is, std::size_t I, bool ... Bs>
    struct bar<std::index_sequence<Is...>, I, true, Bs...>
       : public bar<std::index_sequence<Is..., I>, I+1U, Bs...>
     { };
    
    // false case
    template <std::size_t ... Is, std::size_t I, bool ... Bs>
    struct bar<std::index_sequence<Is...>, I, false, Bs...>
       : public bar<std::index_sequence<Is...>, I+1U, Bs...>
     { };
    
    // end case
    template <typename T, std::size_t I>
    struct bar<T, I>
     { using type = T; };
    
    template <bool ... Bs>
    struct foo : public bar<std::index_sequence<>, 0U, Bs...>
     { };
    
    int main()
     {
       static_assert( std::is_same<typename foo<false, true, true>::type,
                                   std::index_sequence<1U, 2U>>{}, "!" );
     }
    

    If you don't like the recursive solutions, I propose (just for fun) another solution based of std::tuple_cat

    #include <tuple>
    #include <utility>
    #include <type_traits>
    
    template <std::size_t, bool>
    struct baz
     { using type = std::tuple<>; };
    
    template <std::size_t I>
    struct baz<I, true>
     { using type = std::tuple<std::integral_constant<std::size_t, I>>; };
    
    template <std::size_t I, bool B>
    using baz_t = typename baz<I, B>::type;
    
    template <typename, bool...>
    struct bar;
    
    template <std::size_t ... Is, bool ... Bs>
    struct bar<std::index_sequence<Is...>, Bs...>
     {
       template <std::size_t ... Js>
       constexpr static std::index_sequence<Js...>
          func (std::tuple<std::integral_constant<std::size_t, Js>...> const &);
    
       using type = decltype(func(std::tuple_cat(baz_t<Is, Bs>{}...)));
     };
    
    
    template <bool ... Bs>
    struct foo : public bar<std::make_index_sequence<sizeof...(Bs)>, Bs...>
     { };
    
    int main()
     {
       static_assert( std::is_same<typename foo<false, true, true>::type,
                                   std::index_sequence<1U, 2U>>{}, "!" );
     }
    
    0 讨论(0)
  • 2021-02-08 20:59

    This code looks correct and works when compiled as C++17. It uses std::array::begin, which only has been made constexpr in C++17.

    A better compilation error can be achieved when using clang, which states:

    <source>:23:25: note: non-constexpr function 'begin' cannot be used in a constant expression
        auto it = array.begin();
    
    0 讨论(0)
提交回复
热议问题