【问题标题】:constexpr function and hardcoded argumentsconstexpr 函数和硬编码参数
【发布时间】:2015-10-13 21:48:41
【问题描述】:

所以通常 constexpr 函数是在编译时执行的函数,当传递给它的参数也是 constexpr 所以如下:

constexpr int function(int x, int y){
   return x+y;
}

参数声明如下:

constexpr int x = 5;
constexpr int y = 6;

将在编译时执行,但参数声明如下:

int x=5;
int y=6;

不会的。我想知道如果我们以下列方式调用这个函数会发生什么:

function(5,6);

从技术角度来看,5 和 6 是右值,但没有办法(我猜)它们可以被强制转换为 constexpr(如果我们可以笼统地说关于强制转换为 constexpr),所以在我看来它将被执行在运行时。但是,没有实际理由在运行时执行它,因为 x 和 y 在编译时都是已知的。

所以我的问题是现实生活中的情况如何?这个函数是在运行时执行还是在编译时执行

【问题讨论】:

  • 字面量也是常量表达式。
  • 如果是这样,请将其发布为答案,我会接受它:)
  • 如果优化器意识到x 和y 将始终具有相同的值,则也可能在编译时评估具有非const x 和y 的调用function(x, y)。只是不需要这样做,并且结果不能用于需要 constexpr 的地方。

标签: c++ c++11 constexpr


【解决方案1】:
constexpr int fun(int x, int y) { return x+y; }
fun(5,6) // << constant expression?

tl;dr

5 和 6 是常量表达式。因此fun(5,6) 也是一个常量表达式,并且将在编译时进行评估,这是强制性的(例如非类型模板)。

东西... 我快速浏览了标准,希望没有遗漏任何重要的点。

我们已经从@42 的回答中知道了:

  • 根据 N4527,int 是 constexpr 函数 的有效参数类型,因为它是文字类型(因为它是标量类型,根据 §3.9/10相同的文档是文字类型)。因此,fun 是一个有效的 constexpr 函数。

  • 它提供的代码将fun(5,6) 放入需要常量表达式并且似乎被某些编译器接受的上下文中。

现在的问题是这是否是有效的、符合标准的行为。

来自 N4527 的§5.20 说:

条件表达式 e 是一个核心常量表达式,除非按照抽象机 (1.9) 的规则对 e 的求值将求出以下表达式之一:

  • 这里有一大堆阻止表达式成为核心常量表达式的事情

该列表不包含“带有常量表达式参数的 constexpr 函数”,因此它们是核心常量表达式(除非它们在使用时未定义)。

因此,如果5 和6 是常量表达式,那么fun(5,6) 是一个常量表达式,如果fun 是一个有效的constexpr 函数并且在使用它之前被定义。给定的函数满足 §7.1.5/3 中要求的约束并且是一个有效的 constexpr 函数。

5 和 6 都是 integer literals 类型 int 根据 §2.13.2

1) 整数字面量是没有句点或指数部分的数字序列,可选的分隔单引号在确定其值时会被忽略。 [...]

2) 整数字面量的类型是表 5 中可以表示其值的相应列表中的第一个。

后缀:none,十进制文字:int、long int、long long int

现在再次查看第 5.20 节,我们看到:两者都是常量表达式。

【讨论】:

  • "因此,如果 5 和 6 是常量表达式,那么如果 fun 声明为 constexpr 并在使用它之前定义,则 fun(5,6) 是一个常量表达式。" ...不,您必须知道fun 在其体内做了什么才能做出裁决-检查this。你把一个简单的问题复杂化了
  • @101010 是的,该函数必须是有效的 constexpr 函数。
【解决方案2】:

根据草案标准N45277.1.5/3 constexpr 说明符 [dcl.constexpr](强调我的):

constexpr 函数的定义应满足以下条件 约束:

(3.1) — 它不能是虚拟的 (10.3);

(3.2) — 它的返回类型应该是文字类型;

(3.3) — 它的每个参数类型都应该是文字类型;

...

因此,调用function(5,6); 满足constexpr 函数的定义,并在编译时执行。

另外,您可以使用std::integral_constant自行测试:

#include <iostream>
#include <type_traits>

constexpr int fun(int x, int y) {
   return x + y;
}

int main() {
    std::cout << std::integral_constant<int, fun(5, 6)>::value << std::endl;
}

LIVE DEMO

如果fun中的输入参数不是constexpr,编译会失败。

【讨论】:

  • “它是有效/有保证的,因为它可以编译”不是一个很好的论点。可能是编译器扩展、编译器错误或其他。
  • @Pixelchemist std::integral_constant 不是编译器扩展。它在标准 [20.10.2 Header 概要 [meta.type.synop] ] 中。
  • 我认为如果您添加标准参考,您的答案会变得更好(并消除可能的误解:它编译 = 它是正确的)。
  • 很抱歉吹毛求疵,但 3.3 指的是constexpr int function(int x, int y),而不是function(5, 6)。
  • @101010 这与integral_constant 无关。在这种情况下,可以使用int 类型的任何非类型模板参数来检查编译器是否会接受需要常量表达式的function(5,6)。仍然没有证明function(5,6) 是一个常量表达式。一个或多个编译器允许它出现在需要常量表达式的地方这一事实并不能证明它的有效性。
猜你喜欢
  • 2019-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 2016-06-15
相关资源
最近更新 更多