首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >运行时使用constexpr错误

运行时使用constexpr错误
EN

Stack Overflow用户
提问于 2018-02-05 13:38:25
回答 2查看 208关注 0票数 2

考虑下面的代码片段

代码语言:javascript
运行
复制
constexpr int divide( int x, int y)
{
    return (x/y);
}

constexpr int div_by_zero( int x)
{
    return (x/0);
}

案例1 :

代码语言:javascript
运行
复制
int x = divide(10,0);

这可以成功编译(使用gcc和clang),但会产生以下运行时错误。

浮点异常(核心转储)

案例2 :

代码语言:javascript
运行
复制
int y = div_by_zero(10);

这就产生了编译错误,

(g++ -std=c++17)除以零不是一个常量表达式 注意:即使在这种情况下,clang也不会抛出错误。

还有编译器警告:

(clang++ -std=c++17),除以零是未定义的-零分制,除以零Wdiv被零。

对于第1种情况,为什么编译器即使在编译时知道第二个参数的值(即零),也不会抱怨?

示例这里除法(10,2);生成以下汇编代码

代码语言:javascript
运行
复制
  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], 5

除法(10,0);在程序集代码下面生成

代码语言:javascript
运行
复制
  mov esi, 0
  mov edi, 10
  call divide(int, int)

当输入为零时,就会调用divide()。当非零值是函数的输入时,也会在编译时计算相同的值。如果编译器能够找出并调用方法而不是计算,那么为什么不能抛出错误呢?

EN

回答 2

Stack Overflow用户

发布于 2018-02-05 18:25:36

divide(10, 0)不警告的事实是实现质量(QoI)问题。你可以向gcc提交一个窃听器。但请注意,这种任意的常量跟踪并不总是可行的。

但是,div_by_zero(10)不编译的事实略有不同。来自[dcl.constexpr]/5

对于既不是默认的也不是模板的constexpr函数或constexpr构造函数,如果不存在参数值,使得对函数或构造函数的调用可以是核心常量表达式的求值子表达式,或者对于构造函数是某个对象的常量初始化器(basic.start.static),则程序的格式不正确,不需要诊断。

构成核心常量表达式的一个限制因素是,它不能调用未定义行为,其中包括除以零

因此,对于divide(),可以传递一些参数,使调用成为有效的常量表达式。但是对于div_by_zero(),不存在任何可以使其成为常量表达式的参数--这使得程序格式不正确。

票数 3
EN

Stack Overflow用户

发布于 2018-02-05 13:46:51

您的函数是constexpr,这意味着当上下文允许它时,它们将被计算为constexpr (编译时)。在您的使用中,上下文不是constexpr,因此将计算推迟到运行时。https://godbolt.org/g/Jo5GyL

代码语言:javascript
运行
复制
int x = div(10, 0); // x isn't a constexpr var, calculation in runtime
constexpr int y = div(10, 0); // y is constexpr, calculation in compile-time + error

在第二个例子中,划分部分定义得很好:x / 0。这就是为什么编译器知道这将失败,并报告错误,即使在编译时没有调用该函数(同样,var y中缺少constexpr )。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48623873

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档