当前位置: 首页 > 知识库问答 >
问题:

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

卢才艺
2023-03-14

我有两个片段。

第一个片段:

#include <string>

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

int main() {
    std::string a;
    if constexpr (foo(a)) {
    }
}

第二段:

#include <string>

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

int main() {
    std::string a;
    std::string& x = a;
    if constexpr (foo(x)) {
    }
}

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

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

共有3个答案

聂涛
2023-03-14

首先,在这两个代码部分中,评估上下文都要求后缀表达式是常量表达式。函数模板foo的定义满足constexpr函数的要求,因为它的参数是文字类型的。id-expression ax 都是 glvalue,其计算决定了对象的身份,但唯一的区别是,在你的拳头代码中。从 需要标识转换复制初始化参数,因为以下规则:

当引用类型的参数直接绑定到参数表达式时,隐式转换序列是标识转换,除非参数表达式的类型是参数类型的派生类,在这种情况下,隐式转换序列是派生到基的转换

由于
[over.ics.scs#2]

如第[conv]条所述,标准转换序列本身就是身份转换(即不转换)

剩下的表达式都是常量表达式。因此,对于foo(a)这个表达式,它是一个常量表达式。

对于foo(x),因为x是引用类型的id表达式,受此规则约束:

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

  • 它用常量表达式初始化或
  • 它的生命周期是从e的评估开始的;

< code>x的生存期在< code>foo(x)的求值之前开始,并且它不是用常数表达式初始化的,因为< code > STD::string a;不是glvalue常量表达式。如果修改< code > STD::string a;到< code > static STD::string a;,那就ok了。

顾承平
2023-03-14

因为您无法在编译时知道x将具有什么值,所以您只知道它将指向a。您所做的是检查x的“值”,但xa所在的地址,您无法知道a将被分配到何处,也无法确定地址是否恒定。

另一方面,你已经知道< code>a的值,它是一个空的std::string。

这个问题包含更多的细节:如何初始化一个constexpr引用

魏波娃
2023-03-14

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

注意<code>foo(a)</code>不计算任何引用。虽然<code>foo</code>的参数是一个引用,但它不会作为表达式计算。事实上,

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

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

标准中的相关部分(无关部分由我删除):

[表达式常数]/2:

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

>

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

    > < li>

    它是用常量表达式或

    它的生命周期始于对E的评估;

    [表达式常量]/6:

    常量表达式是一个glvalue核心常量表达式,它指的是常量表达式(如下定义)的允许结果的实体,…如果一个实体是一个具有静态存储持续时间的对象,而不是一个临时对象,或者是一个值满足上述约束的临时对象,或者它是一个函数,那么它就是一个常量表达式的允许结果。

  •  类似资料:
    • 问题内容: 在研究Angularjs的FEQ时,我看到了以下文章: $ rootScope存在,但可以用于邪恶 Angular中的范围形成一个层次结构,原型通常是从​​树顶部的根范围继承。通常这可以忽略不计,因为大多数视图都有自己的控制器,因此也有自己的作用域。 有时,有些数据要对整个应用程序进行全局处理。对于这些,您可以像其他作用域一样在其上注入并设置值。由于作用域是从根作用域继承而来的,因此这

    • 问题内容: 我正在使用ApplicationTestCase测试一个Android应用程序。我想模拟我的AsyncTasks之一(示例简化为显示问题): 因此,为了设置测试,我做了以下工作: 然后,实际测试如下: 但是运行时出现异常: 为什么模拟AsyncTask的技术不起作用? 请注意,在这种简单情况下,删除会导致问题消失,但是对于我的实际测试,我确实需要创建应用程序。 问题答案: AsyncT

    • 问题内容: 在下面的代码中,我试图使h1元素具有最高利润。当我在css中将位置设置为inline时,未显示上边距。但是,当我将其更改为inline-block时,它确实可以。我想知道是否有人可以解释为什么会这样。谢谢。 这是我的HTML: 这是CSS 问题答案: CSS2规范的9.2.4节规定: inline-block 此值使元素生成一个 内联级块容器 。内联块的内部被格式化为块框,元素本身被格

    • 问题内容: 我试图按照教程进行操作,但是此代码对我不起作用。有人可以解释为什么以及如何解决吗?我认为这与ng-controller有关,但不确定为什么。 问题答案: 您的代码无法与angular 1.3+一起使用,因为您正在将控制器定义为全局函数。 从AngularJS文档中: 从1.2迁移到1.3 控制器 由于3f2232b5,$ controller将不再在窗口上查找控制器。在控制器上查看窗口

    • 我有一个简单的测试设置,如 但当我尝试编译测试时,我会遇到53个错误,比如 实际上并没有传达任何关于问题所在的有用信息。我只能假设在我的构建中没有正确配置某些内容。sbt文件或其他地方。 这段代码确实曾经工作过,在我清理东西的过程中,事情发生了变化,现在它被破坏了,没有好的诊断。 有人能提出要找的东西吗?

    • 问题内容: 我已经在端口8080(默认)下启动并测试了Tomcat。现在,我将连接器端口更改为80,并重新启动了Tomcat,在最小的Debian 6.0安装中没有任何显示。现在,这里的窍门在哪里? 问题答案: 转到/ etc / default / tomcat6并更改为