非类型模板参数能否为"void *"类型? [英] Can a non-type template parameter be of type "void*"?
问题描述
类型为
void*
的非类型模板参数不允许在 至少是该标准的某些版本.
Non-type template parameters of type
void*
are not allowed in at least some versions of the standard.
这是真的吗?
如果为真,则在哪些版本的标准中不允许类型为void*
的非类型模板参数?
Is this true?
If it is true, in which versions of the standard are non-type template parameters of type void*
not allowed?
(注意:如
评论
回答
另一条评论,
这是关于非类型模板参数的,
不是模板类型参数,
可以是每个有效的 type-id
[temp.arg.type] ,
包括void*
.
(Note: as noted in
a comment
to answer
another comment,
this is about non-type template parameters,
not template type arguments,
which can be any valid type-id per
[temp.arg.type],
including void*
.
推荐答案
TL; DR
类型为void*
的模板参数自C ++ 20起有效.
它们在C ++ 20之前无效.
TL;DR
Template parameters of type void*
are valid since C++20.
They are invalid prior to C++20.
C ++ 20放宽了对非类型模板参数类型的限制, 因此,我们首先对其进行调查.
C++20 relaxed the restrictions on the type of a non-type template parameter, so let's investigate it first.
当前草案(截至UTC 2019年5月6日10:00)在 [temp.param]/4 :
The current draft (as of UTC 10:00, May 6, 2019) says in [temp.param]/4:
非类型 template-parameter 必须具有以下之一 (可选,具有简历资格)类型:
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
- 具有强结构等式([class.compare.default])的文字类型,
- 左值引用类型
- 包含占位符类型([dcl.spec.auto])的类型,或
- 推论类类型([dcl.type.class.deduct])的占位符.
- a literal type that has strong structural equality ([class.compare.default]),
- an lvalue reference type,
- a type that contains a placeholder type ([dcl.spec.auto]), or
- a placeholder for a deduced class type ([dcl.type.class.deduct]).
void*
是指针类型.
指针类型是标量类型( [基本.types]/9 ).
标量类型是文字类型(
void*
is a pointer type.
A pointer type is a scalar type ([basic.types]/9).
A scalar type is a literal type ([basic.types]/10).
Therefore, void*
is a literal type.
The first bullet is the relevant one.
进一步跟踪, [class.compare.default]/3 说:
如果给定的全值
x
为,则类型 C
具有强烈的结构相等性 键入const C
,或者:
A type
C
has strong structural equality if, given a glvaluex
of typeconst C
, either:
-
C
是非类类型,x <=> x
是类型std::strong_ordering
或std::strong_equality
或
C
is a non-class type andx <=> x
is a valid expression of typestd::strong_ordering
orstd::strong_equality
, or
C
是具有==
运算符的类类型,该运算符在C
的定义中默认定义,x == x
在上下文中格式正确
转换为bool
的所有C
基类子对象,并且都是非静态的
数据成员具有很强的结构相等性,并且C
没有mutable
或volatile
子对象.
C
is a class type with an ==
operator defined as defaulted in the definition of C
, x == x
is well-formed when contextually
converted to bool
, all of C
's base class subobjects and non-static
data members have strong structural equality, and C
has no mutable
or volatile
subobjects.
void*
是非类类型,
所以第一个项目符号是相关的.
现在,问题归结为x <=> x
的类型
其中,x
是类型为void* const
的glvalue(不是const void*
).
根据 [expr.spaceship]/8 :
void*
is a non-class type,
so the first bullet is relevant.
Now the question boils down to the type of x <=> x
where x
is a glvalue of type void* const
(not const void*
).
Per [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]).否则,结果将不确定.
If the composite pointer type is an object pointer type,
p <=> q
is of typestd::strong_ordering
. If two pointer operandsp
andq
compare equal ([expr.eq]),p <=> q
yieldsstd::strong_ordering::equal
; ifp
andq
compare unequal,p <=> q
yieldsstd::strong_ordering::less
ifq
compares greater thanp
andstd::strong_ordering::greater
ifp
compares greater thanq
([expr.rel]). Otherwise, the result is unspecified.
Note that void*
is an object pointer type ([basic.compound]/3).
Therefore, x <=> x
is of type std::strong_ordering
.
Thus the type void*
has strong structural equality.
因此,在当前的C ++ 20草案中,
允许将void*
作为模板参数类型的类型.
Therefore, in the current C++20 draft,
void*
is allowed as the type of a template parameter type.
现在,我们解决C ++ 17问题. [temp.param] 说:
Now we address C++17. [temp.param] says:
非类型 template-parameter 必须具有以下之一 (可选,具有简历资格)类型:
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
- 整数或枚举类型
- 指向对象的指针或指向函数的指针,
- 对对象的左值引用或对函数的左值引用,
- 成员的指针,
-
std::nullptr_t
或 - 包含占位符类型的类型.
- integral or enumeration type,
- pointer to object or pointer to function,
- lvalue reference to object or lvalue reference to function,
- pointer to member,
std::nullptr_t
, or- a type that contains a placeholder type.
请注意,指向对象的指针"不包含void*
每个 [basic.compound]/3 :
Note that "pointer to object" doesn't include void*
per [basic.compound]/3:
[注意:"指向
void
的指针没有指针到对象的类型,因为void
不是对象类型. — 尾注]
[ Note: A pointer to
void
does not have a pointer-to-object type, however, becausevoid
is not an object type. — end note ]
以上六个项目符号均不包含void*
作为模板参数的可能类型.
因此,在C ++ 17中,
模板参数的类型不得为void*
.
None of the above six bullets include void*
as a possible type of a template parameter.
Therefore, in C++17,
a template parameter shall not have type void*
.
C ++ 11和C ++ 14的措辞相同
除了不存在有关占位符类型的项目符号.
一般来说,
在C ++ 20之前,
模板参数的类型不得为void*
.
The wording is the same for C++11 and C++14
except that the bullet about placeholder types are not there.
In general,
prior to C++20,
a template parameter shall not have type void*
.
T.C. 在 评论 没有人诊断出这个IHRC. 让我们测试一下编译器是否在C ++ 17模式下进行诊断 并显示以下最小示例:
T.C. says in a comment that nobody diagnoses this IHRC. Let's test whether compilers diagnose that in C++17 mode with the minimal example shown below:
template <void*>
class C {};
int main()
{
C<nullptr> x;
(void) x;
}
代码可以在以下位置编译并正常运行 GCC 9.1.0 , GCC 8.3.0 , GCC 7.3.0 , GCC 6.3.0 , GCC 5.5.0 , C 8.0.0 , C 7.0.0 , C 6.0.1 , 和 C 5.0.0 .
The code compiles and runs fine on GCC 9.1.0, GCC 8.3.0, GCC 7.3.0, GCC 6.3.0, GCC 5.5.0, Clang 8.0.0, Clang 7.0.0, Clang 6.0.1, and Clang 5.0.0.
NathanOliver told me in a comment that someone told him some compilers will error, but the major ones don't. Therefore, as far as I am able to confirm here, T.C.'s statement is correct — nobody diagnoses this.
这篇关于非类型模板参数能否为"void *"类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!