[英]C++ constexpr : Compute a std array at compile time
I want to convert an "array" of bool
to a integer sequence. 我想将bool
的“数组”转换为整数序列。 So I need to compute an std::array
at compile time. 所以我需要在编译时计算一个std::array
。
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 the line that call the computeIndices
function. 我收到调用computeIndices
函数的行的错误。 Is this code c++14 correct? 这段代码c ++ 14是否正确? Is it possible to do otherwise? 是否可以这样做? I am using MSVC and I get this error : expression did not evaluate to a constant 我正在使用MSVC,我得到这个错误:表达式没有评估为常量
This code looks correct and works when compiled as C++17. 此代码看起来正确,并在编译为C ++ 17时有效。 It uses std::array::begin
, which only has been made constexpr
in C++17. 它使用std::array::begin
,它只在C ++ 17中成为constexpr
。
A better compilation error can be achieved when using clang , which states: 使用clang时可以实现更好的编译错误,其中指出:
<source>:23:25: note: non-constexpr function 'begin' cannot be used in a constant expression
auto it = array.begin();
Is it possible to do otherwise? 是否可以这样做?
About correctness answered JVApen (+1). 关于正确性回答了JVApen(+1)。
A possible alternative is avoid std::array
at all and construct the index sequence in a recursive way using template specialization 一种可能的替代方法是完全避免使用std::array
,并使用模板特化以递归方式构造索引序列
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
如果您不喜欢递归解决方案,我建议(只是为了好玩)另一种基于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>>{}, "!" );
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.