非类型模板参数可以是 "void*" 类型吗?
Can a non-type template parameter be of type "void*"?
Non-type template parameters of type void*
are not allowed in at
least some versions of the standard.
这是真的吗?
如果为真,在哪些版本的标准中不允许 void*
类型的非类型模板参数?
(注意:如
回答
,
这是关于非类型模板参数,
不是 模板类型参数,
可以是任何有效的 type-id
[temp.arg.type],
包括 void*
.
TL;DR
void*
类型的模板参数自 C++20 起有效。
它们在 C++20 之前无效。
C++20
C++20放宽了对非类型模板参数类型的限制,
所以让我们先调查一下。
当前草案(截至 UTC 10:00,2019 年 5 月 6 日)在 [temp.param]/4 中表示:
A non-type template-parameter shall have one of the following
(optionally cv-qualified) types:
- 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*
是指针类型。
指针类型是 标量类型 ([basic.types]/9)。
标量类型是文字类型 ([basic.types]/10)。
因此,void*
是 文字类型 。
第一个项目符号是相关的。
进一步追踪,[class.compare.default]/3 说:
A type C
has strong structural equality if, given a glvalue x
of
type const C
, either:
C
is a non-class type and x <=> x
is a valid expression of type std::strong_ordering
or std::strong_equality
, or
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*
是非class类型,
所以第一个项目符号是相关的。
现在问题归结为 x <=> x
的类型
其中 x
是 void* const
类型的左值(不是 const void*
)。
每 [expr.spaceship]/8:
If the composite pointer type is an object pointer type, p <=> q
is
of type std::strong_ordering
. If two pointer operands p
and q
compare equal ([expr.eq]), p <=> q
yields
std::strong_ordering::equal
; if p
and q
compare unequal, p <=>
q
yields std::strong_ordering::less
if q
compares greater than
p
and std::strong_ordering::greater
if p
compares greater than
q
([expr.rel]). Otherwise, the result is unspecified.
请注意 void*
是一个 对象指针类型 ([basic.compound]/3)。
因此,x <=> x
是 std::strong_ordering
类型。
因此类型 void*
具有 强结构等式 .
因此,在当前的 C++20 草案中,
void*
允许作为模板参数类型的类型。
C++17
现在我们介绍 C++17。
[temp.param] 说:
A non-type template-parameter shall have one of the following
(optionally cv-qualified) types:
- 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.
请注意 "pointer to object" 不包括 void*
每 [basic.compound]/3:
[ Note: A pointer to void
does not have a pointer-to-object type, however, because void
is not an object type. — end note ]
None 以上六个项目符号包括 void*
作为模板参数的可能类型。
因此,在 C++17 中,
模板参数不应具有类型 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,
GCC 7.3.0,
GCC 6.3.0,
GCC 5.5.0,
Clang 8.0.0,
Clang 7.0.0,
Clang 6.0.1,
和 Clang 5.0.0.
NathanOliver told me in a 有人告诉他有些编译器会出错,但主要的不会。因此,就我在这里可以确认的而言,T.C. 的说法是正确的——没有人对此进行诊断。
Non-type template parameters of type
void*
are not allowed in at least some versions of the standard.
这是真的吗?
如果为真,在哪些版本的标准中不允许 void*
类型的非类型模板参数?
(注意:如
void*
.
TL;DR
void*
类型的模板参数自 C++20 起有效。
它们在 C++20 之前无效。
C++20
C++20放宽了对非类型模板参数类型的限制, 所以让我们先调查一下。
当前草案(截至 UTC 10:00,2019 年 5 月 6 日)在 [temp.param]/4 中表示:
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
- 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*
是指针类型。
指针类型是 标量类型 ([basic.types]/9)。
标量类型是文字类型 ([basic.types]/10)。
因此,void*
是 文字类型 。
第一个项目符号是相关的。
进一步追踪,[class.compare.default]/3 说:
A type
C
has strong structural equality if, given a glvaluex
of typeconst C
, either:
C
is a non-class type andx <=> x
is a valid expression of typestd::strong_ordering
orstd::strong_equality
, or
C
is a class type with an==
operator defined as defaulted in the definition ofC
,x == x
is well-formed when contextually converted tobool
, all ofC
's base class subobjects and non-static data members have strong structural equality, andC
has nomutable
orvolatile
subobjects.
void*
是非class类型,
所以第一个项目符号是相关的。
现在问题归结为 x <=> x
的类型
其中 x
是 void* const
类型的左值(不是 const void*
)。
每 [expr.spaceship]/8:
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.
请注意 void*
是一个 对象指针类型 ([basic.compound]/3)。
因此,x <=> x
是 std::strong_ordering
类型。
因此类型 void*
具有 强结构等式 .
因此,在当前的 C++20 草案中,
void*
允许作为模板参数类型的类型。
C++17
现在我们介绍 C++17。 [temp.param] 说:
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
- 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.
请注意 "pointer to object" 不包括 void*
每 [basic.compound]/3:
[ Note: A pointer to
void
does not have a pointer-to-object type, however, becausevoid
is not an object type. — end note ]
None 以上六个项目符号包括 void*
作为模板参数的可能类型。
因此,在 C++17 中,
模板参数不应具有类型 void*
.
C++11 和 C++14 的措辞相同
除了关于占位符类型的项目符号不存在。
一般来说,
在 C++20 之前,
模板参数不应具有类型 void*
.
但是编译器会诊断这个吗?
T.C. 表示
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, Clang 8.0.0, Clang 7.0.0, Clang 6.0.1, 和 Clang 5.0.0.
NathanOliver told me in a