类模板的require子句是否必须在成员定义之外重复?

问题描述

在类之外定义了使用requires子句的类模板的成员时,如果未指定gccrequires不会抱怨,而clang会声明

请考虑以下代码段:

#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

这是一个要报告的错误吗?

解决方法

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

[临时班级]

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

[临时链接]

6如果两个模板头相同,则它们是等效的 模板参数列表具有相同的长度,对应 template-parameters是等效的,并且都用 类型约束,如果其中一个模板参数为 用类型约束声明,如果任何一个模板头都有一个 要求条款,它们都有要求条款,并且 相应的约束表达式是等效的。

等价的模板头要求它们都具有一个等效的require子句。完全省略它会等效。

,

来自[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<Container>中的任何功能都不匹配。

(我尚未为此找到公开的GCC错误报告)