为什么constexpr函数的行为与参考不同?

时间:2019-10-20 11:18:40

标签: c++ constexpr

受到Counting function arguments at compile time

的启发

考虑this code

template <typename... Args>
constexpr int count(Args&&...)
{
    return sizeof...(Args);
}

void foo(int value)
{
    static_assert(count(value) >= 0);  // OK

    const int& ref = 7;
    static_assert(count(ref) >= 0);  // Error
}

第一个static_assert工作正常。第二个错误:

<source>:12:19: error: static_assert expression is not an integral constant expression
    static_assert(count(ref) >= 0);
                  ^~~~~~~~~~~~~~~
<source>:12:25: note: initializer of 'ref' is not a constant expression
    static_assert(count(ref) >= 0);
                        ^
<source>:11:16: note: declared here
    const int& ref = 7;
               ^

两种情况都令我惊讶。为什么在编译时显然不知道static_assert的情况下,第一个value可以正常工作?为什么第二个static_assert不起作用,而与第一个{唯一的根本区别是它提供了引用而不是值?

1 个答案:

答案 0 :(得分:3)

与常量表达式一样,我们需要查阅 [expr.const] 中的列表,看看是否禁止编写任何子表达式。在这种情况下,相关的项目符号就是这个:

  

2.11一个id表达式,它引用引用类型的变量或数据成员,除非引用具有前面的初始化,并且   要么

     
      
  • 使用常量表达式或
  • 进行初始化   
  • 其寿命始于e的评估;
  •   

这就是将ref击倒的原因。由于count(ref)的赋值是事先声明的,因此它不存在于求值中,并且未使用常量表达式进行初始化。可能是7,但是实际的初始化程序是一个临时对象,因为这是引用绑定的对象。

对于value可用。这是因为没有禁止value本身的项目符号。现在,引用参数的生命周期始于对count(value)的求值,而不是事先求值。因此,这是在常量表达式中创建的有效引用,但不能用于读取value