为什么引用不能与编译时函数一起使用?

nic*_*lai 2 c++ compile-time constant-expression constexpr c++17

我有两个片段。

第一个片段:

#include <string>

template <typename T>
constexpr bool foo(T&&) {
    return false;
}

int main() {
    std::string a;
    if constexpr (foo(a)) {
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个片段:

#include <string>

template <typename T>
constexpr bool foo(T&&) {
    return false;
}

int main() {
    std::string a;
    std::string& x = a;
    if constexpr (foo(x)) {
    }
}
Run Code Online (Sandbox Code Playgroud)

第一个编译,但第二个不编译(错误消息:错误:'x' 的值在常量表达式中不可用。为什么?为什么a在常量表达式中可用,而x不是?

该命令,用于编译g++ -std=c++17 main.cpp.

xsk*_*xzr 6

因为通常常量表达式无法评估引用具有自动存储持续时间的对象的引用。这里我的意思是通过确定对象的身份不是通过确定对象的价值来“评估” 。因此,即使a您的示例中不需要对象的值(即不应用左值到右值的转换),foo(x)仍然不是常量表达式。

Notefoo(a)不评估任何参考。尽管参数 offoo是一个引用,但它不会被评估为表达式。事实上,即使它被评估,例如,

template <typename T>
constexpr bool foo(T&& t) {
    t;
    return false;
}
Run Code Online (Sandbox Code Playgroud)

foo(a)仍然是一个常量表达式。这种情况是例外,因为引用t的评估中初始化的foo(a)


标准中的相关部分(我省略了不相关的部分):

[表达式常量]/2 :

表达式 e 是核心常量表达式,除非按照抽象机器的规则对 e 求值会求值以下表达式之一:

  • ...

  • 引用变量或引用类型数据成员的 id 表达式,除非该引用具有前面的初始化并且

    • 它用常量表达式初始化或

    • 它的生命周期开始于 e 的计算;

  • ...

[表达式常量]/6 :

常量表达式可以是一个glvalue芯常量表达式指的是一个常量表达式的结果允许的实体(如下面所定义),...的实体是一个允许的常量表达式的结果,如果它是与物体的静态不是临时对象或者是值满足上述约束的临时对象,或者是一个函数的存储持续时间