在纯C++中实现 Linux 内核的 __is_constexpr (ICE_P) 宏

Implementing the Linux Kernel's __is_constexpr (ICE_P) macro in pure C++

本文关键字:constexpr ICE is 在纯 实现 Linux 内核 C++      更新时间:2023-10-16

在阅读了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 都是空指针常量,则std​::​nullptr_­t;
  • 如果 p1 或
  • 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_PC++中无法启动。