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

时间:2017-12-09 07:48:45

标签: c++ c++14 constexpr

来自这个问题:  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术语。

1 个答案:

答案 0 :(得分:2)

constexpr函数意味着可以在编译时评估函数的值。由于输入true可以使用,因此该函数是有效的constexpr。请记住,constexpr函数可以将地址作为常规函数,它不需要是编译时间,只有当用作编译时函数时(在您的示例中不是这样)。

正如cppreference上的constexpr页面所述:

  

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

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

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

作为W.F.在注释中提到,该函数可以用于编译时,但仅用于有效输入,即不会导致不是编译时常量的子表达式的输入。因此输入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

特别参见标准文件中的例子。