非类型模板参数可以为“ void *”类型吗?

时间:2019-05-06 10:18:13

标签: c++ pointers templates language-lawyer c++17

Yakk - Adam Nevraumont said

  

不允许在void*类型的非类型模板参数   至少是该标准的某些版本。

这是真的吗? 如果是这样,则在哪个版本的标准中不允许使用void*类型的非类型模板参数?

(注意:如 a comment 回答 another comment, 这是关于非类型模板参数的, 不是模板类型参数, 可以是每个有效的 type-id [temp.arg.type], 包括void*

1 个答案:

答案 0 :(得分:11)

TL; DR

void*类型的模板参数自C ++ 20起有效。 它们在C ++ 20之前无效。

C ++ 20

C ++ 20放宽了对非类型模板参数类型的限制, 因此,我们首先对其进行调查。

当前草案(截至UTC 2019年5月6日10:00)在[temp.param]/4中表示:

  

非类型 template-parameter 必须具有以下之一   (可选,具有简历资格)类型:

     
      
  • 具有强结构等式([class.compare.default])的文字类型,
  •   
  • 左值引用类型
  •   
  • 包含占位符类型([dcl.spec.auto])的类型,或
  •   
  • 推导类类型([dcl.type.class.deduct])的占位符。
  •   

void*是指针类型。 指针类型是标量类型[basic.types]/9)。 标量类型文字类型[basic.types]/10)。 因此,void*文字类型。 第一颗是相关的。

进一步跟踪,[class.compare.default]/3说:

  

如果给定C的glvalue为x,则类型const C具有强结构相等性   输入C,或者:

     
      
  • x <=> x是非类类型,而std::strong_ordering是类型std::strong_equalityC

  • 的有效表达式   
  • ==是一个类类型,其C运算符定义为x == x的定义中的默认值,bool在上下文中格式正确   C的所有基类子对象都转换为C,并且是非静态的   数据成员具有很强的结构平等性,并且mutable没有volatile   或void*子对象。

  •   

x <=> x是非类类型, 所以第一个项目符号是相关的。 现在,问题归结为x的类型 其中void* const是类型const void*(不是p <=> q)的glvalue。 根据{{​​3}}:

  

如果复合指针类型为对象指针类型,则std::strong_­ordering为   p类型的。如果两个指针操作数qp <=> q   比较等于([expr.eq]),std::strong_­ordering::equal得出   p;如果qp <=> q比较不相等,则std::strong_­ordering::less得出q,如果p比较大于   std::strong_­ordering::greaterp如果q比较大于   void*([expr.rel])。否则,结果不确定。

请注意,x <=> x对象指针类型[expr.spaceship]/8)。 因此,std::strong_ordering的类型为void*。 因此,类型void*具有强结构相等性

因此,在当前的C ++ 20草案中, 模板参数类型可以使用std​::​nullptr_­t

C ++ 17

现在,我们解决C ++ 17问题。 [basic.compound]/3说:

  

非类型 template-parameter 必须具有以下之一   (可选,具有简历资格)类型:

     
      
  • 整数或枚举类型
  •   
  • 指向对象的指针或指向函数的指针,
  •   
  • 对对象的左值引用或对函数的左值引用
  •   
  • 成员的指针,
  •   
  • void*
  •   
  • 包含占位符类型的类型。
  •   

请注意,“指向对象的指针”不包含void[temp.param]

  

[注意:”指向void的指针没有指向对象的指针类型,因为void*不是对象类型。 — 尾注]

以上六个项目符号均不包含void* 作为模板参数的可能类型。 因此,在C ++ 17中, 模板参数的类型不得为void*

C ++ 11和C ++ 14的措辞相同 除了不存在有关占位符类型的项目符号。 一般来说, 在C ++ 20之前, 模板参数的类型不得为template <void*> class C {}; C<nullptr> x;

但是编译器会诊断出来吗?

[basic.compound]/3T.C. 没有人诊断出这个IHRC。 让我们测试一下编译器是否在C ++ 17模式下进行诊断 并显示以下最小示例:

arules

代码在以下位置编译并运行良好 commentGCC 9.1.0GCC 8.3.0GCC 7.3.0GCC 6.3.0GCC 5.5.0Clang 8.0.0Clang 7.0.0, 和Clang 6.0.1

因此,TC的说法是正确的。