C ++ constexpr: compute std array at compile time

I want to convert a bool array to an entire sequence. So I need to compute std::array at compile time.

Here is my code

 #include <array> template<typename InputIt, typename T > inline constexpr typename std::iterator_traits<InputIt>::difference_type count( InputIt first, InputIt last, const T &value ) { typename std::iterator_traits<InputIt>::difference_type ret = 0; for (; first != last; ++first) { if (*first == value) { ret++; } } return ret; } template<bool ..._values> struct keep_value { static constexpr std::size_t numberOfValues = sizeof...(_values); static constexpr bool values[] = {_values...}; static constexpr std::size_t numberToKeep = count(values, values + numberOfValues, true); static constexpr std::array<std::size_t, numberToKeep> computeIndices() { std::array<std::size_t, numberToKeep> array{}; auto it = array.begin(); for(std::size_t i{0}; i < numberOfValues; ++i) if(values[i] == true) *it++ = i; return array; } static constexpr std::array<std::size_t, numberToKeep> indices = computeIndices(); template<typename Indices = std::make_index_sequence<numberToKeep>> struct as_index_sequence{}; template<std::size_t ...Is> struct as_index_sequence<std::index_sequence<Is...>> : std::index_sequence<indices[Is]...>{}; }; int main() { keep_value<false, true, true>::template as_index_sequence<>{}; // Should return the sequence 1 2 } 

I get an error for a line calling the computeIndices function. Is this C ++ 14 code correct? Can this be done otherwise? I use MSVC and I get this error: expression was not evaluated by constant

+7
c ++ template-meta-programming c ++ 14 constexpr variadic-templates
source share
2 answers

This code looks correct and works when compiling C ++ 17. It uses std::array::begin , which was only made constexpr in C ++ 17.

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

 <source>:23:25: note: non-constexpr function 'begin' cannot be used in a constant expression auto it = array.begin(); 
+7
source share

Is it possible otherwise?

About the correctness of the answer JVApen (+1).

A possible alternative is to avoid std::array altogether and construct the index sequence in a recursive manner using specialized specialization

Below is a complete compiled 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 recursive solutions, I suggest (just for fun) another solution based on 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>>{}, "!" ); } 
+2
source share

All Articles