C++11 constexpr 函数传递参数

标签 c++ 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)
}

最佳答案

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

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

constexpr 函数是一个函数,如果使用 constexpr 参数求值, 在其执行期间表现“正确”,将被求值在编译时。

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

函数的

constexpr 是对如何编写函数的文档和限制以及对编译器的说明的混合体。

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

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

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

有很多方法可以解决这个问题。我最喜欢的是 std::integer_constantstd::variant;您可以选择哪个在运行时处于事件状态,然后 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);

关于C++11 constexpr 函数传递参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23569309/

相关文章:

c++ - 在 O(1) 复杂度 C++ 中删除 vector<int> 的最后 n 个元素?

c++ - Box2D 实体之间的层次连接

c++ - 从 sscanf 中提取数据

C++ : Trim a string to a single char, 然后将该字符转换为 float

c++ - 强制编译时 constexpr

c++ - 如何初始化 constexpr 引用

c++ - 如何从 QThread::run() 获取用户反馈,例如Q消息框?

c++ - 等价于 C++11 线程中的 WAIT_ABANDONED

c++ - 如果函数被称为 constexpr,则有条件地 static_assert

c++ - OpenGL 中的地形小 map ?