【问题标题】:Does a class template's requires clause have to be repeated outside member definitions?类模板的 requires 子句是否必须在成员定义之外重复?
【发布时间】:2020-08-28 06:41:48
【问题描述】:

当使用requires 子句的类模板的成员在类外部定义时,如果未指定requiresgcc 不会报错,而clang 会报错。

考虑下面的代码 sn-p:

#include <concepts>

template<typename Container>
    requires std::integral<typename Container::value_type>
class Foo {
public:
    void func();
};

template<typename Container>
void Foo<Container>::func()
{}

使用gcc 编译不会报错。

clang 报告以下错误:

❯ clang++ -std=c++2a test.cpp
test.cpp:10:1: error: requires clause differs in template redeclaration
template<typename Container>
^
test.cpp:4:19: note: previous template declaration is here
    requires std::integral<typename Container::value_type>
                  ^
1 error generated.

如果我将定义更改如下:

template<typename Container>
    requires std::integral<typename Container::value_type>
void Foo<Container>::func()
{}

现在clang 不会抱怨了。

gcc --version 的输出:

gcc (GCC) 10.2.0

clang --version 的输出:

clang version 10.0.1 
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

这是要报告的错误吗?

【问题讨论】:

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


    【解决方案1】:

    应该为 GCC 提交一个错误,因为它接受代码,即使类外成员的声明没有等效的模板头。

    [temp.class]

    3当一个成员函数,一个成员类,一个成员枚举,一个 静态数据成员或类模板的成员模板是 定义在类模板定义之外,成员定义被定义为一个模板定义,其中 template-head 等价于类模板 ([temp.over.link])。

    [temp.over.link]

    6 两个模板头是等价的,如果他们 模板参数列表具有相同的长度,对应 模板参数是等价的,并且都用 如果任一模板参数为 使用类型约束声明,并且 如果任一模板头具有 requires-clause,它们都有 requires-clauses 和 相应的约束表达式是等价的。

    templates-heads 的等价性要求两者都有一个等价的 requires 子句。省略它完全破坏了等价性。

    【讨论】:

    【解决方案2】:

    来自[temp.mem.func]/1 [摘录,强调我的]:

    类模板的成员函数可以在 声明它的类模板定义。 [例子:

    受约束的成员函数可以不合规地定义:

    template<typename T> concept C = requires {
      typename T::type;
    };
    
    template<typename T> struct S {
      void f() requires C<T>;
      void g() requires C<T>;
    };
    
    template<typename T>
      void S<T>::f() requires C<T> { }  // OK
    template<typename T>
      void S<T>::g() { }                // error: no matching function in S<T>
    

    ——结束示例]

    特别注意(非规范性)文本的最后一个示例。

    因此,Clang 拒绝是正确的,而 GCC 接受第一个程序作为外联定义是错误的

    template<typename Container>
    void Foo<Container>::func() {}
    

    不匹配Foo&lt;Container&gt;中的任何函数。

    (我还没有找到公开的 GCC 错误报告)

    【讨论】:

    • 这不是格式错误的 NDR。 OP 示例中的模板头在功能上并不等效。这是可以诊断的。
    • @StoryTeller-UnslanderMonica 啊,你是对的 - 非偶函数等价是停止的地方(而不是像我那样陷入等价兔子洞)。谢谢。
    猜你喜欢
    • 2020-11-29
    • 2022-11-25
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    相关资源
    最近更新 更多