在纯C++中实现 Linux 内核的 __is_constexpr (ICE_P) 宏
Implementing the Linux Kernel's __is_constexpr (ICE_P) macro in pure C++
在阅读了Martin Uecker的ICE_P
谓词的标准C11版本后,我尝试以纯C++来实现它。C11版本,利用_Generic
选择如下:
#define ICE_P(x) _Generic((1? (void *) ((x)*0) : (int *) 0), int*: 1, void*: 0)
C++的明显方法是用模板和decltype
替换_Generic
,例如:
template<typename T> struct is_ice_helper;
template<> struct is_ice_helper<void*> { enum { value = false }; };
template<> struct is_ice_helper<int*> { enum { value = true }; };
#define ICE_P(x) (is_ice_helper<decltype(1? (void *) ((x)*0) : (int *) 0)>::value)
但是,它未能通过最简单的测试。为什么它检测不到整数常量表达式?
这个问题很微妙。确定条件表达式指针操作数的复合类型的规范在C++与 C 中的规范相似,因此它开始看起来很有希望:
(N4659)[参考资料]
7 Lvalue-to-rvalue、数组到指针和函数到指针 标准转换对第二个和第三个操作数执行。 转换后,下列情况之一应成立:
[...]
第二个和第三个操作数中的一个或两个具有指针类型;指针转换、函数指针转换和限定 执行转换以将它们带到其复合指针 类型(子句 [expr])。结果为复合指针类型。
[...]
复合指针类型的缩减指定如下:
(N4659)[扩展]
5 两个操作数 p1 和 p2 的复合指针类型具有 分别键入 T1 和 T2,其中至少一个是指针或 指向成员类型或
std::nullptr_t
的指针为:
- 如果 p1 和 p2 都是空指针常量,则
如果 p1 或std::nullptr_t
;- p2 是空指针常量,则分别为 T2 或 T1;
如果 T1- 或 T2 是"指向 cv1 void 的指针",而另一种类型是"指向 cv2 T 的指针",其中 T 是对象类型或 void,则为"指向 cv12 void 的指针", 其中 CV12 是 CV1 和 CV2 的并集;
- [...]
因此,我们ICE_P
宏的结果取决于我们在按顺序检查每个子弹后降落上面的哪个子弹。鉴于我们如何定义is_ice_helper
,我们知道复合类型不是nullptr_t
,否则我们会点击第一个项目符号,并且由于缺少模板专用化而出现错误。因此,我们必须命中第 3 号子弹,使谓词报告为假。这一切似乎都取决于空指针常量的定义。
(N4659)[转换ptr](强调我的)
1空指针常量是具有值的整数文本零或
std::nullptr_t
类型的 prvalue 。空指针 常量可以转换为指针类型;结果为空 该类型的指针值,并且与其他所有指针值区分开来 对象指针或函数指针类型的值。这样的转换是 称为空指针转换。相同的两个空指针值 类型应相等。将空指针常量转换为 指向 CV 限定类型的指针是单个转换,而不是 指针转换后跟限定的顺序 转换。可以转换整型空指针常量 到std::nullptr_t
类型的 prvalue 。
由于根据上述定义,(int*)0
不是空指针常量,因此我们不符合 [expr]/5 的第一个项目符号的条件。复合类型不是std::nullptr_t
。(void *) ((x)*0)
既不是空指针常量,也不能转换为空指针常量。删除演员表(定义不允许的)给我们留下了(x)*0
.这是一个值为零的整数常量表达式。但它不是值为零的整数文字!C++ 中空指针常量的定义与 C 中的定义不同!
(N1570)6.3.2.3 指针
3 值为 0 的整数常量表达式,或这样的 转换为类型
void *
的表达式称为空指针常量。如果 空指针常量转换为指针类型,结果为 指针,称为空指针,保证与 指向任何对象或函数的指针。
C 允许值为零的任意常量表达式形成空指针常量,而 C++ 需要整数文本。鉴于C++对计算各种文字类型的常量表达式的丰富支持,这似乎是一个不必要的限制。并且使上述方法ICE_P
C++中无法启动。
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 多成员Constexpr结构初始化
- 条件constexpr函数
- constexpr 函数中的非文字(通过 std::is_constant_evaluated)
- Visual C++ constexpr Hints
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 为什么constexpr的性能比正常表达式差
- 是否可以使用if constexpr删除控制流语句
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 为什么std::isnan 不是 constexpr?
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 更多constexpr容器是否需要mark_immutable_if_consexpr
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- constexpr上下文中std::initializer_list的验证
- constexpr构造函数需要常量成员函数时出现问题
- vs 2015 constexpr变量不恒定,但与2019相比还好吗
- C++constexpr实现差异
- 添加静态constexpr成员是否会更改结构/类的内存映射
- C++中的Constexpr迭代程序