【问题标题】:constexpr and std::cout working on function but not in lambdaconstexpr 和 std::cout 处理函数但不在 lambda 中
【发布时间】:2019-06-12 18:20:28
【问题描述】:

为什么constexpr 不能与std::cout 一起使用,但可以与printf 一起使用?

#include <iostream>
constexpr void f() { std::cout << ""; } //error
constexpr void g() { printf(""); } //ok

为什么std::cout 与 lambdas constexpr 一起使用?

#include <iostream>
int main () {
    auto h = []() constexpr { std::cout << ""; }; //ok
}

【问题讨论】:

  • 在 godbolt.org 上使用 gcc 9.1

标签: c++ c++17 constexpr cout


【解决方案1】:

从技术上讲,它不适用于其中任何一个。

来自[dcl.constexr]

对于既不是默认值也不是模板的 constexpr 函数或 constexpr 构造函数,如果不存在参数值,则函数或构造函数的调用可以是核心常量表达式的求值子表达式,或者,对于构造函数,某些对象的常量初始化器([basic.start.static]),程序格式错误,不需要诊断

f()g() 从来都不是常量表达式(std::cout &lt;&lt; xprintf() 都不是 constexpr 函数),所以 constexpr 声明格式不正确。但是编译器不是需要来诊断这个(在这种情况下,它可能很容易,但在一般情况下......不是那么多)。您所看到的是,您的编译器能够诊断出一个问题,但不能诊断出另一个问题。

但他们都错了。

【讨论】:

  • 像这样的东西真的让我感到厌烦。似乎如此 神秘且难以发现这样的错误。嗯,这一切!
  • @LightnessRacesinOrbit 实际上,通常很难诊断“你标记了这个constexpr,但这是不可能的”。所以如果编译器这样做会很好,但就像......这并不重要。如果您尝试将其用作常量表达式,它肯定不会编译。
  • 我抱怨的更多是语言而不是编译器。完全荒谬的是,这种“简单”的代码格式错误,编译器很难诊断,更不用说程序员了!
  • @LightnessRacesinOrbit 比难更难。这是无法确定的。就图灵机而言,这与停机问题密切相关。 确实如此
  • @alterigel 通常无法确定。如问题所示,在某些情况下可能会发出诊断信息。但这就是我的观点:该语言的一些据称最简单的新特性在范围和性质上几乎完全是学术性的(阅读:安全使用它们需要 C++ 学位)
【解决方案2】:

它没有。您需要使用它来强制编译时错误。

constexpr int a = f(), 0; // fails
constexpr int b = g(), 0; // fails

constexpr 从不产生常量表达式的函数是格式错误的;无需诊断。这意味着编译器会尽最大努力检查是否是这种情况,但无论哪种方式,您的程序都已经出现错误。似乎 gcc 看不到 printf 不是常量表达式。 clang errors at the definition.

【讨论】:

  • 很好地使用逗号运算符:)
  • 那么 lambda 对象呢?它必须编译吗?根据我从您的回答中了解到,没有。
  • @JoãoPaulo 那里也一样。这是一个错误,但编译器不需要出错。
  • 上面sn-p中逗号的意义是什么?强制对 lhs 求值的逗号运算符表达式?
  • @dfri 我需要一种方法来强制对函数进行持续评估,并且由于它返回 void,因此我无法将其分配给变量。所以我在 constexpr 变量的初始化程序中使用了逗号运算符,以便在编译时评估函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-01
  • 1970-01-01
  • 2011-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多