c++ - 为什么在这个 constexpr 函数中允许 std::swap ?
问题描述
我写了一个计算两个数字的 gcd 的函数,它std::swap
在第二个参数大于第一个参数的情况下使用。
一段时间后,我意识到std::swap
不是,但 constexpr
我的函数仍然编译并成功运行。
我尝试使用 MinGW-w64 8.1.0 和 Visual C++ 2017 并且两者都适用。
我的第一个想法是因为constexpr
允许在运行时执行函数,所以我尝试std::integral_constant<int,gcd(32,12)>
了,它成功了。
但是,我不能使用我自己的任何非 constexpr 函数(这是我所期望的)。
这是我的测试代码:
#include <utility>
inline void foo() noexcept {
}
template<typename T>
constexpr T gcd(T a, T b) {
// foo(); // only works with non-constexpr j
if(a<b) {
std::swap(a, b); // works for both constexpr i and non-constexpr j
}
if(b==0) {
return a;
} else {
return gcd(b, a%b);
}
}
int main()
{
constexpr int i = std::integral_constant<int, gcd(32, 12)>::value;
int j = gcd(32,12);
}
所以,我的问题是:为什么我可以std::swap
在我的函数中使用?
解决方案
constexpr 函数必须满足以下要求:
- ...
- 至少存在一组参数值,因此函数的调用可以是核心常量表达式的求值子表达式
有一条不经过的路std::swap()
,在哪里a>=b
。事实上,因为gcd(32, 12)
执行永远不会通过std::swap()
。
编辑:我看了C++14 草案。第7.1.5 节 constexpr 说明符。第 5 段说:
对于非模板、非默认 constexpr 函数 [...],如果不存在参数值,则函数或构造函数的调用可以是核心常量表达式 (5.20) 的评估子表达式,或者,对于构造函数,某个对象的常量初始化器(3.6.2),程序格式错误;
他们给出的例子是:
constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
推荐阅读
- java - 如何创建重叠布局?
- javascript - 对动态块中的父元素使用 ref React
- ruby - 如何在内部类中使用属性?
- node.js - 一个用于客户端 + 服务器 React 项目的 package.json?
- node.js - MongoDB 文档迁移
- java - 如何在 @ContextConfiguration 初始化程序之前启动 kafka 测试容器?
- php - 如何使用 PHP 将 MYSQL 数据库记录放在变量中?
- sql-server - 如何从 SQL Server 中的另一个用户定义函数更新存储过程中的表变量?
- angular - 如何像 typescript 中的数组一样解析 Json 对象。MAP Firestore 内的 MAP
- php - Puppeteer 使用 browsershot 创建 pdf - headerHtml 和 footerHtml 错误