gpt4 book ai didi

C++ "forgetting"该变量在用作函数参数时是 constexpr

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:07:55 26 4
gpt4 key购买 nike

我有以下代码,编译器无法看到作为参数传递给函数的变量是 constexpr,这让我很恼火,因此我必须使用 arity 0 函数而不是 1 参数函数。

我知道这不是编译器错误,但我想知道是否有可以解决此问题的习语。

#include <array>
#include <iostream>

static constexpr std::array<int, 5> arr{11, 22, 33, 44, 55};

template <typename C, typename P, typename Y>
static constexpr void copy_if(const C& rng, P p, Y yi3ld) {
for (const auto& elem: rng) {
if (p(elem)){
yi3ld(elem);
}
}
}

// template<std::size_t N>
static constexpr auto get_evens(/* const std::array<int, N>& arr */) {
constexpr auto is_even = [](const int i) constexpr {return i % 2 == 0;};
constexpr int cnt = [/* &arr, */&is_even]() constexpr {
int cnt = 0;
auto increment = [&cnt] (const auto&){cnt++;};
copy_if(arr, is_even, increment);
return cnt;
}();
std::array<int, cnt> result{};
int idx = 0;
copy_if(arr, is_even, [&result, &idx](const auto& val){ result[idx++] = val;});
return result;
}

int main() {
// constexpr std::array<int, 5> arr{11, 22, 33, 44, 55};
for (const int i:get_evens(/* arr */)) {
std::cout << i << " " << std::endl;
}
}

如果我想要的不是很明显:我想更改 get_evens签名,以便它是基于数组大小 N 的模板模板,并且它需要 1 个类型为 const std::array<int, N>& 的参数.

更改arr时的错误信息成为函数参数没有帮助:

prog.cc:25:21: note: initializer of 'cnt' is not a constant expression prog.cc:19:19: note: declared here constexpr int cnt = [&arr, &is_even]()constexpr {

最佳答案

函数参数永远不是常量表达式,即使在 constexpr 上下文中使用函数也是如此:

constexpr int foo(int i)
{
// i is not a constexpr
return i + 1;
}

constexpr auto i = 1;
constexpr auto j = foo(i);

要模拟 constexpr 参数,请使用模板参数:

template<int i>
constexpr int foo()
{
// i is constexpr
return i + 1;
}

constexpr auto i = 1;
constexpr auto j = foo<i>();

一个可能的解决方案是使用 std::integer_sequence 将整数编码成一个类型:

#include <array>
#include <iostream>
#include <type_traits>

template<typename P, typename Y, int... elements>
constexpr void copy_if_impl(P p, Y yi3ld, std::integer_sequence<int, elements...>) {
((p(elements) && (yi3ld(elements), true)), ...);
}

template<typename arr_t, typename P, typename Y>
constexpr void copy_if(P p, Y yi3ld) {
copy_if_impl(p, yi3ld, arr_t{});
}

template<typename arr_t>
constexpr auto get_evens(){
constexpr auto is_even = [](const int i) constexpr { return i % 2 == 0; };
constexpr int cnt = [&is_even]() constexpr {
int cnt = 0;
auto increment = [&cnt](const auto&) { cnt++; };
copy_if<arr_t>(is_even, increment);
return cnt;
}();

std::array<int, cnt> result{};
int idx = 0;
copy_if<arr_t>(is_even, [&result, &idx](const auto& val) {
result[idx++] = val; });
return result;
}

int main()
{
using arr = std::integer_sequence<int, 11, 22, 33, 44, 55>;
for (const int i : get_evens<arr>()) {
std::cout << i << " " << std::endl;
}
}

Constantinos Glynos 建议的添加。

摘自 Scott MeyersEffective Modern C++ 一书,第 15 项,第 98 页:

  • constexpr functions can be used in contexts that demand compile-time constants. If the values of the arguments you pass to a constexpr function in such a context are known during compilation, the result will be computed during compilation. If any of the arguments’ values is not known during compilation, your code will be rejected.
  • When a constexpr function is called with one or more values that are not known during compilation, it acts like a normal function, computing its result at runtime. This means you don’t need two functions to perform the same operation, one for compile-time constants and one for all other values. The constexpr function does it all.

关于C++ "forgetting"该变量在用作函数参数时是 constexpr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52812160/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com