非类型模板参数可以是 "void*" 类型吗?
Can a non-type template parameter be of type "void*"?
Yakk - Adam Nevraumont说:
不允许在
void*
至少是标准的某些版本。
这是真的吗? 如果为 true,则不允许在哪些版本的标准中使用void*
类型的非类型模板参数?
(注:如 一条评论 回答 另一条评论, 这是关于非类型模板参数, 不是模板类型参数, 可以是每个[温度参数类型], 包括void*
.
TL;博士
类型为void*
的模板参数自 C++20 起有效。 它们在 C++20 之前无效。
C++20
C++20 放宽了对非类型模板参数类型的限制, 因此,让我们先调查一下。
当前草案(截至 UTC 2019 年 5 月 6 日 10:00)在 [temp.param]/4 中说:
非类型模板参数应具有以下项之一 (可选符合 CV 标准)类型:
- 具有强结构相等性的文本类型([class.compare.default]),
- 左值引用类型,
- 包含占位符类型 ([dcl.spec.auto]) 的类型,或
- 推导类类型的占位符 ([dcl.type.class.deduct])。
void*
是指针类型。 指针类型是标量类型([basic.types]/9)。标量类型是文本类型([basic.types]/10)。 因此,void*
是文本类型。 第一个项目符号是相关的项目符号。
进一步追踪,[class.compare.default]/3 说:
具有强结构相等性的
C
,如果给定 glvaluex
键入const C
,任:
C
是非类类型,x <=> x
是类型std::strong_ordering
或std::strong_equality
的有效表达式,或
C
是一个类类型,其==
运算符定义为C
定义中的默认值,x == x
在上下文中格式良好 转换为bool
,C
的所有基类子对象和非静态 数据成员具有很强的结构平等性,C
没有mutable
或volatile
子对象。
void*
是非类类型, 所以第一个项目符号是相关的。 现在问题归结为x <=> x
的类型 其中x
是类型为void* const
(不是const void*
)的 glvalue 。 每 [expr.spaceship]/8:
如果复合指针类型是对象指针类型,则
p <=> q
类型std::strong_ordering
.如果两个指针操作数p
和q
比较相等([expr.eq]),p <=> q
收益率std::strong_ordering::equal
;如果p
和q
比较不相等,则p <=> q
产生std::strong_ordering::less
如果q
大于p
和std::strong_ordering::greater
如果p
比较大于q
([expr.rel])。否则,结果未指定。
请注意,void*
是对象指针类型([basic.compound]/3)。 因此,x <=> x
属于std::strong_ordering
型。 因此,void*
型具有很强的结构平等性。
因此,在目前的C++20草案中, 允许void*
作为模板参数类型的类型。
C++17
现在我们解决C++17。 [温度参数] 说:
非类型模板参数应具有以下项之一 (可选符合 CV 标准)类型:
- 整数或枚举类型,
指向- 对象的指针或指向函数的指针,
对对象的左值引用- 或对函数的左值引用,
- 指向成员的指针,
std::nullptr_t
或- 包含占位符类型的类型。
请注意,"指向对象的指针"不包括void*
每 [基本化合物]/3:
[注意:但是,指向
void
的指针没有指向对象的指针类型,因为void
不是对象类型。
以上六个项目符号均不包括void*
作为模板参数的可能类型。 因此,在第 17 C++, 模板参数不应具有类型void*
。
C++11 和 C++14 的措辞相同 除了关于占位符类型的项目符号不存在。 通常在C++20之前, 模板参数不应具有类型void*
。
但是编译器会诊断出这一点吗?
T.C.在 评论 没有人诊断这个IHRC。 让我们测试编译器是否在 C++17 模式下诊断出这一点 最小示例如下所示:
template <void*>
class C {};
int main()
{
C<nullptr> x;
(void) x;
}
代码编译并运行良好 GCC 9.1.0, GCC 8.3.0, 海湾合作委员会 7.3.0, GCC 6.3.0, GCC 5.5.0, 叮当 8.0.0, 叮当 7.0.0, 叮当 6.0.1, 和 Clang 5.0.0。
NathanOliver在评论中告诉我,有人告诉他一些编译器会出错,但主要的编译器不会。 因此,据我在这里能够证实,T.C.的说法是正确的——没有人诊断这一点。
- 引用一个已擦除类型(void*)的指针
- 错误:"cast"未命名类型void setCastDescription(std::string
- 错误:对类型 'const ItemInstance' 的引用无法绑定到类型 'void' 的右值
- 从类型"void*"到函数指针的强制转换无效
- C++错误(从不兼容的类型"void"分配给树节点*)
- 从不兼容的类型 'void (Button::*)(int)' 分配给'void (*)(int)'
- 从类型"void*"到类member_function指针的强制转换无效
- 将 false 转换为指针类型 void*
- 称为对象类型"void (B::*)(int)"不是函数或函数指针
- CPP(15): 错误 C2182:"输入":"非法使用类型"void"
- 类型 "void (Biometria::*)(char *idSensor, GRCAP_FINGER_EVENTS event)" 的参数与类型 "GRCAP_STATUS_EVENT_PROC
- Xcode 变量具有不完整的类型 void
- qvector.h(74):错误 C2182:'t':非法使用类型 'void'
- C 函数声明对类型"void(*fcn)(void*)"参数的说明
- C++从类型“void*”转换为类型“double”无效
- LAMBDA 错误:类型 'void' 的条件表达式是非法的
- 类型 void 的值不允许在 C++ 中出错
- 从类型 'MyStruct' 转换为类型 'void*' 无效
- C++,参数类型(void*&)的目的是什么?
- 无法将不完整类型'void *'的参数转换为'const bitData'