【问题标题】:Can a non-type template parameter be of type "void*"?非类型模板参数可以是“void*”类型吗?
【发布时间】:2019-09-23 23:15:34
【问题描述】:

Yakk - Adam Nevraumont said:

void* 类型的非类型模板参数不允许在 at 至少有一些版本的标准。

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

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

【问题讨论】:

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


    【解决方案1】:

    TL;DR

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

    C++20

    C++20 放宽了对非类型模板参数类型的限制, 所以让我们先调查一下。

    当前草案(截至 2019 年 5 月 6 日 10:00 UTC)在[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 说:

    如果给定一个左值 x 输入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*)。 每[expr.spaceship]/8:

    如果复合指针类型是对象指针类型,p &lt;=&gt; q 是 std::strong_­ordering 类型。如果两个指针操作数p 和q 比较相等 ([expr.eq]),p &lt;=&gt; 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 &lt;=&gt; x 的类型为 std::strong_ordering。 因此void* 类型具有强结构相等性。

    因此,在当前的 C++20 草案中, void* 允许作为模板参数类型的类型。

    C++17

    现在我们讨论 C++17。 [temp.param] 说:

    非类型模板参数应具有以下之一 (可选 cv 限定)类型:

    • 整数或枚举类型,
    • 指向对象的指针或指向函数的指针,
    • 对对象的左值引用或对函数的左值引用,
    • 指向成员的指针,
    • std​::​nullptr_­t,或
    • 包含占位符类型的类型。

    请注意,“指向对象的指针”不包括 void* 每[basic.compound]/3:

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

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

    C++11 和 C++14 的措辞相同 除了关于占位符类型的项目符号不存在。 一般来说, 在 C++20 之前, 模板参数的类型不得为void*。

    但是编译器会诊断这个吗?

    T.C. 说 comment 没有人诊断出这个 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 在comment 中告诉我,有人告诉他一些编译器会出错,但主要的编译器不会。因此,据我在这里可以确认,T.C. 的说法是正确的——没有人对此做出诊断。

    【讨论】:

    • 没有人通过 IIRC 诊断出来。
    • 这到底是在说什么?我一直都能做到vector&lt;void*&gt;。
    • @Joshua 这是关于template &lt;void*&gt; struct X { }; -- 不是关于template &lt;typename T&gt; struct Y { }; Y&lt;void*&gt;();
    猜你喜欢
    • 2012-10-25
    • 1970-01-01
    • 2020-10-01
    • 2018-02-12
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    相关资源
    最近更新 更多