在某些情况下允许从constexpr调用非constexpr函数

Kla*_*aus 5 c++ constexpr c++14

来自这个问题: 如何构建自定义宏,用作constexpr(如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 );
}
Run Code Online (Sandbox Code Playgroud)

有人可以解释标准中给出了哪些规则吗?正如WF的评论:如果将constexpr术语用作模板参数,则如果条件导致对非constexpr函数的求值,则失败。

assert如果将结果用在constexpr术语中,那将直接在编译时抱怨。

Tom*_*sen 7

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

正如constexprcppreference页面上提到的:

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

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

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

正如注释中提到的 WF,该函数可以在编译时使用,但仅适用于有效输入,即不会导致不是编译时常量的子表达式的输入。所以输入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
Run Code Online (Sandbox Code Playgroud)

请特别参阅标准文档中的示例。