C++14 constexpr编译期计算std::array报错,求正确性判断与替代方案
First, let's break down your questions clearly:
1. Does your code comply with the C++14 standard?
It depends on the exact implementation of computeIndices, but if it follows C14's constexpr rules (no runtime-only operations, uses allowed constexpr constructs like loops or simple arithmetic), it should be standard-compliant. The MSVC error expression did not evaluate to a constant often comes down to compiler-specific limitations—MSVC was slower to fully roll out C14 constexpr support compared to GCC or Clang. For example, some loop patterns or std::array manipulations that are legal in C++14 might still be treated as non-constant expressions by older MSVC versions.
2. Alternative C++14-compliant implementations
Here are two reliable ways to convert a boolean array to an index sequence at compile time:
Option 1: Template metaprogramming with index sequences
This uses recursive templates to collect indices where the boolean value is true, with zero runtime overhead:
#include <array> #include <cstddef> #include <utility> namespace detail { // Recursive helper to gather indices for true values template <std::size_t CurrentIdx, bool CurrentBool, bool... RestBools, std::size_t... CollectedIndices> constexpr auto build_index_array(std::index_sequence<CollectedIndices...>) { if (CurrentBool) { return build_index_array<CurrentIdx + 1, RestBools...>( std::index_sequence<CollectedIndices..., CurrentIdx>{} ); } else { return build_index_array<CurrentIdx + 1, RestBools...>( std::index_sequence<CollectedIndices...>{} ); } } // Termination case for recursion template <std::size_t CurrentIdx> constexpr auto build_index_array(std::index_sequence<>) { return std::array<std::size_t, 0>{}; } } // Public interface: takes a pack of bools and returns the index array template <bool... Bools> constexpr auto bools_to_indices() { return detail::build_index_array<0, Bools...>(std::index_sequence<>{}); } // Example usage: constexpr auto indices = bools_to_indices<true, false, true, true>(); // indices will be std::array<std::size_t, 3>{0, 2, 3}
Option 2: Constexpr functions with compile-time counting
If you're working with a std::array<bool, N> instead of a bool pack, this approach first counts true values at compile time, then builds the index array:
#include <array> #include <cstddef> // Count true values in the boolean array (compile-time) template <std::size_t N> constexpr std::size_t count_true_values(const std::array<bool, N>& bool_array) { std::size_t count = 0; for (std::size_t i = 0; i < N; ++i) { count += bool_array[i]; } return count; } // Build index array using precomputed true value count template <std::size_t N, std::size_t TrueCount = count_true_values(std::array<bool, N>{})> constexpr std::array<std::size_t, TrueCount> compute_indices(const std::array<bool, N>& bool_array) { std::array<std::size_t, TrueCount> result{}; std::size_t current_idx = 0; for (std::size_t i = 0; i < N; ++i) { if (bool_array[i]) { result[current_idx++] = i; } } return result; } // Example usage: constexpr std::array<bool, 4> bools = {true, false, true, true}; constexpr auto indices = compute_indices(bools); // indices will be std::array<std::size_t, 3>{0, 2, 3}
Note that for the second option, some older MSVC versions might require you to explicitly pass TrueCount as a template argument (instead of relying on automatic deduction) to avoid the "not a constant expression" error.
内容的提问来源于stack exchange,提问作者Antoine Morrier

