问题标签 [constexpr-function]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
88 浏览

c++ - [decl.constexpr].5 到底是什么意思?

constexpr 函数的标准在[decl.constexpr] 的第 5 点下声明:

对于非模板、非默认的 constexpr 函数或非模板、非默认、非继承的 constexpr 构造函数,如果不存在参数值,则函数或构造函数的调用可以是核心常量的求值子表达式表达式 (5.19),程序格式错误;无需诊断。

它继续为此给出以下示例:

我从中得到的是,具有空参数列表的函数是无诊断格式的。这让我觉得非常奇怪,以至于我怀疑我的理解是不正确的。例如,这是否也是格式错误的:

如果是这样,这背后的基本原理是什么,如果不是,那么限定是什么意思/什么时候 constexpr 函数格式不正确?


大概下面的都可以吧?

0 投票
1 回答
687 浏览

c++ - constexpr 字符串文字检查:语法短,没有运行时的可能性

编辑:重命名,因为我的最终解决方案不使用中毒方法。

我正在寻找一种方法来防止在运行时调用 constexpr 方法。我正在编写一个接受字符串文字的函数,所以我不能简单地使用 NTTP 作为需要constexpr参数的方式:

因为这样即使是合法的 constexpr 使用也会变得很麻烦,需要值具有静态链接,并且您不能输入字符串文字。我想要做:

原因是因为我根据值列表检查字符串,并希望静态检查参数是否包含在允许的集合中。我可以很容易地做到这一点:只需throw()'ing 一个constexpr函数,就可能导致编译时错误。但我不希望生成带有一些导致程序在运行时退出的分支的生产代码的可能性。这将在我的领域造成一个重大问题;此功能在执行“其他重要事情”的程序中是一项不错的功能,如果程序终止,则会发生坏事。

我读到了一大堆可能的方法来做到这一点:

  1. 使用 C++20 consteval- 没有 C++20
  2. 使用 C++20 std::is_constant_evaluated- 没有 C++20
  3. 通过将结果返回给未定义的符号(例如extern int i,从未定义的符号)在运行时毒化方法。如果在编译时调用该方法,编译器永远不会创建返回该符号的代码,但如果在运行时调用该方法,它会创建返回该符号的代码,从而导致链接错误。工作,但丑陋的链接器错误;不是我最喜欢的。我的帖子中显示了一个版本:Constexpr functions not called at compile-time if result is ignored
  4. 在 C++17 中,noexcept自动添加到对constexpr在上下文中实际调用的函数的任何调用constexpr中。所以你可以做noexcept(foo(1))vs noexcept(foo(i))for constexpr int foo(int i)(未明确声明noexcept) 来检测是否i导致调用为constexpr/not。但是您不能在constexpr接受了某些参数的函数中执行此操作 - 您需要从调用站点执行此操作。所以:可能需要一个辅助宏(不是我最喜欢的,但它有效)。
  5. 如果 lambda 范围之外的某些变量不是,则创建一个返回类型无效的 lambda constexpr。这篇文章详细介绍:https ://stackoverflow.com/a/40413051

所以我倾向于使用#3 或#4 + 宏,但是***这篇文章是关于#5 ***,或者是全新的想法。

例如,任何人都可以想出一种没有 lambda 的方法来执行 #5 吗?在那之后,我想看看我是否可以想出一种在constexpr函数本身中使用它的方法,而不是要求它从调用站点使用。现在,如果在运行时调用函数,只需尝试毒化constexpr它,忘记“检测”函数调用是否为constexpr.

我可以像作者一样通过在其中创建一个 lambda 来重新创建 #5 的结果main,但这实际上并不是很有用,而且我仍然不相信它是完全合法的。首先,任何可以用 lambda 完成的事情都可以在没有 lambda 的情况下完成——对吧???如果没有 lambda,我什至无法让原作者的方法工作。这似乎是让它在main().

以下是我尝试在没有 lambda 的情况下重新创建 #5 的几个想法。具有十亿多个排列的实时示例,但都不起作用:https ://onlinegdb.com/B1oRjpTGP

还有一件事:我考虑制作一个预定义的允许标签列表(将字符串包装在一个结构中,这样它就可以是一个 NTTP),并将它们放在某种容器中,然后有一个方法来检索他们。问题是:(1)调用站点语法使用它们变得非常冗长,(2)虽然调用站点使用类似的语法很好,但MyTags::TAG_ONE我的程序需要能够知道完整的集合标签的数量,因此它们需要位于数组或模板变量中,(3)使用数组不起作用,因为获取数组元素会产生一个rvalue,它没有链接,因此不能作为NTTP,(4)使用具有显式特化的模板变量来定义每个标签需要模板变量是全局范围的,这对我来说效果不佳......

这是我能做的最好的了——我觉得这有点丑……:

0 投票
1 回答
145 浏览

c++ - constexpr 构造函数不被称为隐式类型转换的 constexpr

我编写了一些代码,它能够根据调用站点提供与给定函数关联的字符串(通过tuple函数指针和并行数组)来调度函数。dispatch 函数不是直接接受字符串,而是接受一个Callable类型,其中 aconst char*可以转换为 a Callable

Callableis的构造函数,并使用基本递归搜索constexpr从注释中查找函数。tuple我已经验证构造函数能够正常工作并创建一个constexpr Callable(包括示例)。由于调度函数接收要传递给Callable's的参数,因此我知道在创建它时'soperator()的预期函数签名。Callableoperator()

我试图在编译时执行两项检查,而它们可以在编译时完成。首先,我检查提供的字符串是否存在于预定义的字符串数组中。其次,我检查与该字符串关联的函数的签名是否与tuple函数指针的预期签名匹配。我在编译时通过在查找函数throw()的方法中创建“友好”错误消息。constexpr

我已经验证了通过创建一个constexpr可调用对象,我在编译时收到了预期的错误消息。这行得通。如果我Dispatcher直接使用 my ,则无法获得编译时消息,让调用站点将字符串转换为Callable. 我知道当我使用运行时参数时,我的调度函数不会在constexpr上下文中被调用——我故意没有创建那个函数constexpr;关键是用运行时值调用它。但我认为隐式转换“发生在调用点”,而不是在被调用函数内。

因此,我认为在类似的调用中dispatcher("one", 1)(调用参数为 1 的第一个函数)看起来像:“one”Callable 在 call-site 处转换为 a ,然后调用为dispatcher(Callable("one"), 1). 这意味着至少可以使用构造constexpr函数。以我的经验,只要您不忽略调用的结果,就可以进行调用,否则就将其作为运行时进行。如果 result 被忽略,请参阅Constexpr 函数在编译时未调用。这不会发生——当转换发生在对我的调度函数的调用中时,转换构造函数会在运行时被调用!constexprconstexpr

有谁知道我可以更改我的代码以在编译时调用转换构造函数的方法吗???我在这篇文章中找到了一个完全不同的解决方案来解决这类一般问题,但坦率地说,我更喜欢下面代码的语法,如果我能让它工作的话。

我不打算在这篇文章的正文中包含上述代码,而是包含一个更规范的示例来演示该行为,并展示我在上面引用的帖子中看到的行为,一体化。

下面的现场演示:https ://onlinegdb.com/r1s1OE77v

我的“真实”问题的现场演示,如果有兴趣:https ://onlinegdb.com/rJCQ2bGXw

首先是“测试夹具”:

现在测试代码:

0 投票
1 回答
293 浏览

c++ - constexpr 构造函数的参数类型 'std::function' 不是文字类型

我正在编写一个简单的 C++ HTTP 服务器框架。在我的Server课堂上,我可以添加Route's. 每个路由都包含一个路径、一个 HTTP 方法和一个Controller(这是在发出请求时要调用的函数管道。)Controller该类是通过接收std::function's 列表(或者更准确地说:)来构造的std::function<void(const HTTPRequest&, HTTPResponse&, Context&)>,但大多数有时(或者我应该每次都说),这Controller将使用 lambda 函数文字列表进行初始化,如下面的代码所示:

在这种情况下,我想让add_route函数 a constexpr,因为如果我错了,请纠正我,constexpr函数可以在编译时执行。

所以,当我做一切的时候constexpr,我发现了以下错误:

我想知道的是:为什么std::function's 不能是文字类型?有没有办法绕过这个限制?

下面是Controller类的代码。我知道还有其他编译错误,但这是我现在要解决的主要问题。提前致谢!

controller.hpp

controller.cpp

0 投票
0 回答
67 浏览

c++ - constexpr 函数仅在声明为看似无关的模板时才有效

以下代码无法编译;g++ 7.3.0 with--std=c++17给出错误信息

constexpr 函数 'constexpr const C operator+(const C&, int)' 的无效返回类型 'const C'
注意:'C' 不是文字,因为 'C' 有一个非平凡的析构函数

好吧,好吧。但是,如果我将看似无关的模板规范添加到operator+

然后它编译并运行,C T按预期打印。

这里发生了什么?如果非平凡的析构函数是编译第一个的障碍,那么当同样的障碍存在时,它怎么能愉快地编译第二个呢?有没有一种很好的解决方法(即不使用template黑客的方法)?我试过inline但没有帮助。

0 投票
1 回答
65 浏览

c++ - constexpr 函数中的 constexpr 常量?

假设我有一个静态函数,它接受一个枚举并返回一个 cstring ptr 进行调试。

该函数可以是 constexpr,但不能保证它总是可以在编译时进行评估。假设它在微控制器上运行,这是来自蓝牙堆栈的信号事件;例如,设备连接、断开连接、数据输入等,用于上下文。所以参数在编译时不一定是已知的。

将 cstrings 也定义为 constexpr 与不定义是否有任何价值、意义或区别?

我的意思的一个浓缩示例:

我正在使用 gcc 为嵌入式微控制器编译 cpp17。通常使用 -Og 或 -Os。

0 投票
2 回答
94 浏览

c++ - 如何使用 std::generate 初始化具有值的 constexpr 数组

例如,如果我想constexpr std::array<int,100>在编译时使用 1-300 的所有 3 的倍数进行初始化,我该怎么做?

我的第一个想法是使用 std::generate,例如:

我收到一个错误,例如<source>:9:52: error: void value not ignored as it ought to be

我不能在这之后使用 std::generate 因为当然,它在那个时候是只读的

谢谢你的帮助

0 投票
1 回答
47 浏览

c++ - c ++如何将constexpr值与运算符[]一起使用

起源问题是我想在模板非类型参数中使用const char*或。char []当然现在不支持了。所以我想写一些代码来转换char[]std::integer_sequence. 但是我发现了一个严重的问题。

https://godbolt.org/z/E5YPTM

f1 没问题,但 f2 和 f3 是错误的。我很困惑......为什么会这样?看起来只有“return xxx[yyy]”对于编译时是可以的。我无法将其存储在值中或将其传递给其他函数。

0 投票
1 回答
97 浏览

c++ - 是什么阻止了这个 constexpr 函数的编译时评估?

我正在研究一个代表微控制器(STM32)的一组硬件引脚的类。选定的引脚在端口上可能不连续,但假定它们是有序的。例如,如果PortSegment创建此对象来表示 PA2、PA3 和 PA6 引脚,我希望能够进行类似的分配segment = 0b101u,设置 PA2 和 PA6 并重置 PA3。

目前我还没有为不连续的引脚实现ctor 。当前一个只允许表示像 PA2、P3 和 PA4 这样的连续引脚。但是,将压缩位(如上例)映射0b101u到实际硬件位的逻辑是针对不连续情况实现的。

我认为像这样的分配segment = 0b101u主要可以在编译时计算,并且只有BSRR在运行时使用预先计算的值加载实际的硬件寄存器(对于 STM32,它处理硬件引脚的原子设置和重置)。不幸的是,这不是发生的情况,要加载的值BSRR也是在运行时计算的。

这是我正在测试的代码的稍微简化和半生不熟的版本。端口选择(GPIOA、GPIOB 等)代码被省略。

selection成员变量表示端口中使用的引脚。例如,0b111100表示使用 PA2、PA3、PA4、PA5。问题是,mapBits()函数在编译时没有被评估。我也尝试使它成为非静态成员函数,但没有任何改变。按照我的逻辑,当类的segment对象被PortSegment创建时,编译时一切都已经知道了,要加载的值BSRR也可以知道。但似乎我错过了一些东西。

我发现的另一个奇怪的事情是,如果我selection >>= 1;mapBits()函数更改为selection <<= 1;(这对算法没有意义),mapBits()可以计算编译时间。

这是Godbolt 中的代码

0 投票
3 回答
72 浏览

c++ - 为什么 constexpr 方法可以正确返回在执行过程中值发生变化的类成员?

我刚刚发现一个constexpr方法可以正确返回在执行过程中发生变化的类成员的值。我的问题是,如果constexpr方法应该在编译时完全评估,这怎么可能?

下面的示例正确输出Value: 0然后Value: 5. 更重要的是,如果我将其更改a.change(5)为编译器无法预测的内容(例如,a.change(atoi(argv[1]))a.change(rand() % 10 + 1)仍然可以工作。为什么?为什么它甚至可以编译?

先感谢您