C 11 constexpr 函数传参

新手上路,请多包涵

考虑以下代码:

 static constexpr int make_const(const int i){
    return i;
}

void t1(const int i)
{
    constexpr int ii = make_const(i);  // error occurs here (i is not a constant expression)
    std::cout<<ii;
}

int main()
{
   t1(12);
}

为什么我在 make_const 调用时出错?


更新

但这一个有效:

 constexpr int t1(const int i)
{
    return make_const(i);
}

但是,这不是:

 template<int i>
constexpr bool do_something(){
    return i;
}

constexpr int t1(const int i)
{
    return do_something<make_const(i)>();   // error occurs here (i is not a constant expression)
}

原文由 tower120 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 959
2 个回答

一个 constexpr 函数和一个 constexpr 变量是相关的,但不同的东西。

constexpr 变量是保证其值在编译时可用的变量。

constexpr 函数是一个函数,如果使用 constexpr 参数进行评估, 并且 在其执行期间表现“正确”,将在编译时评估。

如果您将非 constexpr int 传递给 constexpr 函数,它不会神奇地使其在编译时进行评估。但是,它将被允许通过自身传递其输入参数的 constexpr (普通函数不能这样做)。

constexpr 函数是文档和对它们的编写方式的限制以及对编译器的指令的混合。

这背后的原因是允许在编译时和运行时评估相同的函数。如果传递运行时参数,则它是运行时函数。如果传递了 constexpr 参数,则可以在编译时对其进行评估(并且如果在某些上下文中使用)。

请注意, consteval 可能是您正在寻找的功能。但也许不是。

您会收到错误,因为通过传入运行时值,您无法获得编译时值。

有办法解决这个问题。我最喜欢的是 std::variantstd::integer_constant ;您可以选择在运行时处于活动状态,然后选择 std::visit 以获得编译时间常数。缺点是这可以很容易地生成 大量 代码。

 template<auto I>
using constant_t=std::integral_constant<decltype(I),I>;
template<auto I>
constexpr constant_t<I> constant_v={};
template<auto...Is>
using var_enum_t=std::variant<constant_t<Is>...>;
template<class Indexes>
struct var_enum_over;
template<class Indexes>
using var_enum_over_t=typename var_enum_over<Indexes>::type;
template<class T,T...ts>
struct var_enum_over<std::integral_sequence<T,Is...>>{
  using type=var_enum_t<Is...>;
};
template<std::size_t N>
using var_index_t=var_enum_over_t<std::make_index_sequence<N>>;

template<std::size_t N>
var_index_t<N> var_index(std::size_t I){
  constexpr auto table=[]<std::size_t...Is>(std::index_sequence<Is...>)->std::array<N,var_index_t<N>>{
    return { var_index_t<N>(constant_v<Is>)..., };
  }(std::make_index_sequence<N>{});
  if (I>=N) throw 0; // todo: something better
  return table[I];
}

(可能有错别字)。

现在你可以:

 auto idx=var_index<5>(3/* 3 can be runtime */);
std::visit([](auto three){
  // three is a compile time value here
}, idx);

原文由 Yakk - Adam Nevraumont 发布,翻译遵循 CC BY-SA 4.0 许可协议

constconstexpr 之间的一个重要区别是 constexpr 可以在编译时进行评估。

通过编写 constexpr int ii = make_const(i); 您告诉编译器该表达式将在编译时进行评估。由于 i 是在运行时评估的,编译器无法执行此操作并给您一个错误。

原文由 TAS 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题