【问题标题】:calling non constexpr function from constexpr allowed in some conditions在某些情况下允许从 constexpr 调用非 constexpr 函数
【发布时间】:2017-12-09 07:48:45
【问题描述】:

来自那个问题: How to build a custom macro that behaves differently when used as constexpr (like assert)?

我想知道为什么可以调用非 constexpr 函数,如果它是有条件的。

void bla( )
{
    std::cout << "bla called!" << std::endl;
}

constexpr bool check(bool condition)
{
    //bla(); // can not directly be called -> not constexpr! 
    condition ? void (0) : bla(); // compiles and runs even if condition is true or false!

    // if condition is const, it did not compile because it
    // directly force execution of non constexpr function
    true ? void(0): bla(); // also that compiles!, ok, directly evaluated
    //true ? bla(): void(0); // that did not compile;)

    //false ? void(0): bla(); // that did not compile;)
    false ? bla(): void(0); // compiles, ok, directly evaluated

    return 0;
}

int main()
{
    check( false );
    check( true );
}

有人能解释一下标准中给出了哪些规则吗? 正如 W.F. 所评论的那样:如果在 constexpr 术语中使用结果,例如 模板参数,如果条件导致评估则失败 非 constexpr 函数。

这使得assert 在编译时直接抱怨如果结果是 在 constexpr 术语中使用。

【问题讨论】:

  • 这就是 constexpr 的工作原理。
  • 衬衫电路禁用bla()... /跨度>
  • @W.F.:由于来自断言宏,它扩展为我在此处编写的内容,因此存在某种差异。如果它不是 constexpr,则将调用 assert 函数。所以这里面还是有一定的玄机的。所以如果更改为in_range( 7, 1, 5 ) 我会得到一个编译错误,对!但是 assert 函数会起作用。但为什么呢?
  • 你能举个例子吗?据我了解,您使用非 constexpr 参数调用 in_range 。这仍然没有放宽函数上给出的 constexpr 条件。
  • @W.F.:我再次简化了我的示例,并且两次都运行了。没有短路,如果 bla 是条件表达式的一部分,则执行 bla。所以我想知道为什么不允许直接调用!

标签: c++ c++14 constexpr


【解决方案1】:

constexpr 函数意味着可以在编译时评估函数的值。由于这对于输入 true 是可能的,因此该函数是有效的 constexpr。请记住,constexpr 函数可以像常规函数一样具有地址,它不需要是编译时,仅在用作编译时函数时(在您的示例中没有)。

正如cppreference 上的constexpr 页面所述:

constexpr 函数必须满足以下要求:

  • 不能是虚拟的
  • 它的返回类型必须是 LiteralType
  • 它的每个参数都必须是 LiteralType
  • 至少存在一组参数值,因此函数的调用可以是核心常量表达式的求值子表达式(对于构造函数,在常量初始化器中使用就足够了)(C++14 起)。违反此项目符号不需要诊断。 (强调我的)

您的函数满足上述所有要求:它不是虚拟的,它返回一个文字类型,参数是文字。更有趣的是最后一个要点:至少存在一组参数值,函数实际上是完全编译时的。 (因此我强调最后一个项目符号)

作为 W.F. cmets中提到,该函数可以在编译时使用,但仅限于有效输入,即不会导致非编译时常量的子表达式的输入。所以输入 true 会起作用,但 false 不会,因为它会导致 bla 被评估。

这在标准中也有说明:§10.1.5.5:

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

constexpr int f(bool b)
{ return b ? throw 0 : 0; }   // OK

constexpr int f() 
{ return f(true); }           // ill-formed, no diagnostic required

具体参见标准文档中的示例。

【讨论】:

    猜你喜欢
    • 2018-07-10
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 2020-07-05
    • 2016-05-13
    • 2017-12-29
    • 1970-01-01
    • 2021-06-29
    相关资源
    最近更新 更多