c++ - static_assert 计算非常量表达式
问题描述
为什么它起作用?
#include <cstdio>
template<auto x> struct constant {
constexpr operator auto() { return x; }
};
constant<true> true_;
static constexpr const bool true__ = true;
template<auto tag> struct registryv2 {
// not constexpr
static auto push() {
fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
//*
return true_; // compiles
/*/
return true__; // read of non-const variable 'x' is not allowed in a constant expression
//*/
}
// not constexpr either
static inline auto x = push();
};
static_assert(registryv2<0>::x);
解决方案
static_assert 计算非常量表达式
不,它肯定不会。常量评估有一组严格的条件,必须遵守才能成功。
对于初学者:
[dcl.dcl]
6在 static_assert-declaration 中,常量表达式应为 bool 类型的上下文转换的常量表达式。
“上下文转换”是“我们将考虑显式转换运算符”的标准术语。它可能变得违反直觉的地方是定义“转换的常量表达式”时。
[expr.const]
4 T 类型的转换后的常量表达式是隐式转换为 T 类型的表达式,其中转换后的表达式是常量表达式,并且隐式转换序列仅包含
- 用户定义的转换,
- [...]
重点在段落的第一句话。转换后的表达式必须是常量表达式。但源表达式不一定是!只要转换顺序仅限于段落中的列表并且是有效的常量评估本身,我们就清楚了。在您的示例中,表达式registryv2<0>::x
具有 type constant<true>
,它可以bool
通过用户定义的转换运算符在上下文中转换为 a 。而且,转换运算符满足 constexpr 函数和常量求值的所有要求。
持续评估的要求列表相当长,所以我不会仔细检查它来验证每个项目符号是否得到支持。但我会证明我们可以绊倒其中一个。
template<auto x> struct constant {
bool const x_ = x;
constexpr explicit operator auto() const { return x_; }
};
此更改立即使godbolt 代码示例格式错误。为什么?因为我们在bool
不允许的情况下对 a 进行左值到右值的转换(访问的标准术语)。
表达式 e 是核心常量表达式,除非按照抽象机的规则对 e 的求值将求值以下表达式之一:
左值到右值的转换,除非它应用于
一个整数或枚举类型的非易失性左值,它引用一个完整的非易失性 const 对象,该对象具有前面的初始化,用常量表达式初始化,或
引用字符串文字的子对象的非易失性泛左值,或
一个非易失性泛左值,它引用一个用 constexpr 定义的非易失性对象,或者引用这种对象的一个非可变子对象,或者
文字类型的非易失性左值,它引用一个非易失性对象,其生命周期在 e 的评估中开始;
回顾例外情况,没有一个适用。所以 nowregistryv2<0>::x
不是类型的上下文转换的常量表达式bool
。
这也解释了为什么true__
1是禁止的。同样的问题,访问不允许的对象。
1 - 这是一个保留的标识符。两个连续的下划线属于任何使用的实现。对手头的问题并不重要,但请注意。
推荐阅读
- namespaces - 为什么我不能在 trait impl 块的匹配臂中使用 Self?
- java - Spring Data Repository - 方法签名
- c# - 将 ASP.NET Core 2.1 和 Angular 6 项目发布到 Azure
- ubuntu - remmina 默认的 ssh 选项是什么?
- php - Laravel 复制数据到其他表,检查是否存在
- node.js - bot builder sdk nodejs builder.Prompts.choice 问题
- c# - https 协议的 Pechkin dll(htmltopdf 转换)样式问题
- android - 如何打开外部音乐播放器(例如 Pulsar、Retro Music Players)并播放我从列表视图中选择的歌曲?
- php - Xampp安装报错:错误运行cmd.exe/C start/MIN net
- python-3.x - 为什么这里会出现错误'行继续字符后的意外字符'?