【问题标题】:GCC disagrees with Clang and MSVC when concept that's always true is used to implement a concept当使用始终正确的概念来实现概念时,GCC 不同意 Clang 和 MSVC
【发布时间】:2021-12-17 17:38:48
【问题描述】:

以下代码使用 Clang 13 和 MSVC v19.29 VS16.11 编译失败,但使用 GCC 11.2 编译成功。

template <typename...>
concept always_true = true;

template <typename T>
concept refable = always_true<T&>;

static_assert(refable<void>);

Clang 13:

<source>:9:1: error: static_assert failed
static_assert(refable<void>);
^             ~~~~~~~~~~~~~
<source>:9:15: note: because 'void' does not satisfy 'refable'
static_assert(refable<void>);
              ^
<source>:7:32: note: because substituted constraint expression is ill-formed: cannot form a reference to 'void'
concept refable = always_true<T&>;
                               ^

MSVC v19.29 VS16.11:

<source>(9): error C2607: static assertion failed

Godbolt

GCC 错了吗?我希望 refable&lt;void&gt; 评估为 false,因为它在直接上下文中形成无效类型 (void&amp;)。

【问题讨论】:

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


    【解决方案1】:
    static_assert(refable<void>);
    

    根据[temp.names]/8refable&lt;void&gt; 是一个concept-id

    concept-idsimple-template-id,其中 template-nameconcept-name时间>。 concept-idbool 类型的纯右值,并且不命名模板特化。 concept-id 计算结果为 true如果概念的规范化 constraint-expression 满足 ([temp.constr.constr])指定模板参数,否则false

    因此,概念的规范化不依赖于命名概念的给定 concept-id 中的模板参数,而是独立执行的东西;然而,concept-id 的使用可能会触发执行一个概念的规范化,[temp.constr.normal]/2:

    [注 1:在确定声明的关联约束 ([temp.constr.constr]) 和评估命名概念特化 ([expr. prim.id])。 ——尾注]

    [temp.constr.normal]/1 涵盖了约束规范化,特别是 /1.4 管理着 OP 的示例:

    表达式 E 的范式是一个约束,定义为 如下:

    • [...]

    • /1.4 concept-id C&lt;A1, A2, ..., An&gt; 的范式是C 的约束表达式的范式 , 将A1, A2, ..., An 替换为C 的相应模板后 每个原子约束的参数映射中的参数。如果 任何此类替换都会导致无效的类型或表达式, 程序格式错误;不需要诊断。

      [示例1:

      template<typename T> concept A = T::value || true;
      template<typename U> concept B = A<U*>;
      template<typename V> concept C = B<V&>;
      

      B 的约束表达式的规范化是有效的并导致 T​::​value(带映射T↦U*∨ true(带空 映射),尽管表达式 T​::​value 对于 a 格式不正确 指针类型TC 的约束表达式结果的规范化 在格式错误的程序中,因为它会形成无效的 在参数映射中键入V&amp;*。 —结束示例]

    这里的关键问题是 OP 的示例是否符合

    在每个原子约束中替换 [...] 参数映射。如果任何此类替换导致无效的类型或表达式,则程序格式错误;不需要诊断。

    或者不。

    然而,refable 的约束表达式的规范化会导致 true(带有一个空映射),重点是这个规范化约束中的空映射。因此,OP 的refable&lt;void&gt; concept-id 的正常形式将替换voidrefable 的规范化形式的参数映射中,但这仅包含一个空参数映射。因此程序不是病态的,在 [temp.constr.normal]/1.4 下的 NDR,并且参数映射永远不会失败,因为在单个空映射中没有任何东西可以替代。

    问题

    refable<void>
    

    导致是否满足(true)约束(false)归结为如何解释[temp.constr.atomic]/3

    要确定是否满足原子约束,首先将参数映射和模板参数代入其表达式。如果替换导致无效的类型或表达式,则不满足约束。 [...]

    这个有点难读清楚(尤其是强调的部分),但是由于参数映射是空的,所以参数映射不会出现替换失败,我将强调的部分解释为模板参数替换为规范化的约束表达式,它不包含模板参数,这意味着没有替换失败。这将证明 GCC 实际上接受该程序是正确的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 1970-01-01
      • 2014-07-15
      • 2023-03-15
      • 1970-01-01
      • 2021-08-30
      • 2019-03-25
      相关资源
      最近更新 更多