【问题标题】:C++ constexpr - Value can be evaluated at compile time?C++ constexpr - 可以在编译时评估值吗?
【发布时间】:2018-09-10 18:50:06
【问题描述】:

我正在阅读关于constexpr here:

constexpr 说明符声明可以在编译时评估函数或变量的值。

当我第一次读到这句话时,它对我来说非常有意义。然而,最近我遇到了一些完全让我失望的代码。我在下面重构了一个简单的例子:

#include <iostream>

void MysteryFunction(int *p);

constexpr int PlusOne(int input) {
  return input + 1;
}

int main() {
  int i = 0;
  MysteryFunction(&i);
  std::cout << PlusOne(i) << std::endl;

  return 0;
}

看这段代码,我无法说出PlusOne(i) 的结果应该是什么,但是它实际上可以编译! (当然链接会失败,但是g++ -std=c++11 -c会成功,不会出错。)

“可能在编译时评估函数的值”的正确解释是什么?

【问题讨论】:

  • 如果你将一个非 constexpr 参数传递给 PlusOne 函数,编译器不能在编译时评估它,它只是一个正常的运行-时间函数。
  • 提示:“constexpr 说明符声明可以在编译时评估函数或变量的值。”
  • FWIW,cppreference 不是 C++ 的“官方描述”。这是一个社区管理的 wiki,尽管它是一个高质量的 wiki。 cppreference 中的语言故意比标准本身更随意。不要将 cppreference 的声明视为具有约束力;如果您想成为语言律师,请参考标准本身(我喜欢这个网站:eel.is/c++draft
  • 我不是想成为一名语言律师,我只是来了解功能。
  • @Apollys 可悲的是,在当今的 C++ 中,这两者通常是不可分离的:P

标签: c++ c++11


【解决方案1】:

constexpr 函数可以在常量表达式中调用,前提是满足对常量表达式求值的其他要求。它也可以在不是常量表达式的表达式中调用,在这种情况下,它的行为与未使用 constexpr 声明的行为相同。正如您问题中的代码所示,调用constexpr 函数的结果自动不是常量表达式。

【讨论】:

  • 这更有意义,这就是我的猜测,但在我看来,这并不是我引用的句子的字面解释。
【解决方案2】:

引用的措辞在某种意义上有点误导。如果你只是孤立地看待PlusOne,并观察它的逻辑,并假设输入在编译时是已知的,那么其中的计算也可以在编译时进行。在其上添加constexpr 关键字可确保我们保持这种可爱的状态并且一切都很好。

但如果输入在编译时不知道,那么它仍然只是一个普通函数,将在运行时调用。

所以constexpr 是函数的属性(“可能在编译时评估”对于某些输入,而不是对于所有输入)不是您的函数/input 在这种特定情况下的组合(所以对于这个特定的输入也不是)。

这有点像函数可以采用const int&amp;,但这并不意味着原始对象必须const。同样,constexpr 在这里对函数添加约束,而不对函数的输入添加约束。

诚然,这一切都是一个巨大的、令人困惑的、模糊的混乱(C++!耶!)。请记住,您的代码描述了程序的含义!它不是不同编译阶段的机器指令的直接配方。

(要真正执行此操作,您需要将整数作为模板参数。)

【讨论】:

  • 这个答案显然是正确的。我只想补充一点,如果您将constexpr 添加到变量中,则会强制执行编译时间。所以 constexpr auto j = PlusOne(i); // main.cpp:13:31: error: 'i' 的值在常量表达式中不可用 constexpr auto j = PlusOne(5); // 好的
【解决方案3】:

“可能在编译时评估函数的值”的正确解释是什么?

如果函数的所有参数在编译时都可以计算,那么函数的返回值可以在编译时计算。

但是,如果函数的参数值仅在运行时已知,则函数的返回值只能在运行时进行评估。

因此,可以在编译时评估函数的值,但这不是必需的。

【讨论】:

  • 谢谢,在我看来,官方描述似乎不完整/措辞不佳。
  • @Apollys,这还不是最糟糕的 :) 看到 actual standard 你就会明白我的意思了。这就是我们需要语言律师的原因。
【解决方案4】:

所有答案都是正确的,但我想举一个简短的例子来解释 constexpr 是多么不直观。

#include <cstdlib>
constexpr int fun(int i){
    if (i==42){
        return 47;
    } else {
        return rand();
    }
}

int main()
{ 
    int arr[fun(42)];
}

附带说明: 有些人觉得 constexpr 状态不令人满意,所以他们建议在语言中添加 constexpr! 关键字。

【讨论】:

猜你喜欢
  • 2021-02-13
  • 2020-10-01
  • 2013-05-26
  • 2012-12-24
  • 2017-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-30
相关资源
最近更新 更多