【问题标题】:C++11 constexpr function pass parameterC++11 constexpr 函数传参
【发布时间】:2014-06-27 11:18:04
【问题描述】:

考虑以下代码:

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)
}

【问题讨论】:

标签: c++ c++11 constexpr


【解决方案1】:

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

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

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

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

函数上的constexpr 混合了文档和对它们的编写方式的限制以及对编译器的说明。

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

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

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

有办法解决这个问题。我最喜欢的是std::variant 中的std::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);

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      因为 t1() 不是 constexpr 函数,所以参数 i 是运行时变量...您不能将其传递给 constexpr 函数。 Constexpr 期望参数在编译时已知。

      【讨论】:

      • 制作 t1 constexpr 不会改变任何东西。
      • 是的,我测试了你的建议。同样的老故事。
      • @MarcGlisse t1() 没有正确形成为 constexpr 函数,我不建议这样做可以解决问题。
      • @praxos1977 - 查看更新的问题。你的建议是错误的。
      • @tower120,我没有提出建议。我指出您不能将运行时变量传递给 constexpr 函数。 TAS 的回答显然比我的措辞更好。
      猜你喜欢
      • 2012-02-21
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      • 2015-11-21
      • 2013-07-04
      • 2013-03-29
      • 2022-01-16
      • 2016-04-21
      相关资源
      最近更新 更多