class 模板的 requires 子句是否必须在成员定义之外重复?
Does a class template's requires clause have to be repeated outside member definitions?
当使用 requires
子句的 class 模板成员定义在 class 之外时,如果 requires
是未指定,而 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
这是要报告的错误吗?
来自[temp.mem.func]/1[摘录,强调我的]:
A member function of a class template may be defined outside of the
class template definition in which it is declared. [Example:
A constrained member function can be defined out of line:
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>
— end example]
特别注意 (non-normative) 文本的最后一个示例。
因此,Clang 拒绝是正确的,而 GCC 接受第一个程序作为 out-of-line 定义是错误的
template<typename Container>
void Foo<Container>::func() {}
不匹配Foo<Container>
中的任何函数。
(我还没有找到一个公开的 GCC 错误报告)
应该为 GCC 提交错误,因为它接受代码,即使 class 之外的成员声明没有等效的 template-head。
[temp.class]
3 When a member function, a member class, a member enumeration, a
static data member or a member template of a class template is
defined outside of the class template definition, the member definition is defined as a template definition in which the
template-head is equivalent to that of the class template ([temp.over.link]).
[temp.over.link]
6 Two template-heads are equivalent if their
template-parameter-lists have the same length, corresponding
template-parameters are equivalent and are both declared with
type-constraints that are equivalent if either template-parameter is
declared with a type-constraint, and if either template-head has a
requires-clause, they both have requires-clauses and the
corresponding constraint-expressions are equivalent.
templates-heads 的等价要求两者都有一个等价的 requires 子句。省略它完全破坏了等价性。
当使用 requires
子句的 class 模板成员定义在 class 之外时,如果 requires
是未指定,而 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
这是要报告的错误吗?
来自[temp.mem.func]/1[摘录,强调我的]:
A member function of a class template may be defined outside of the class template definition in which it is declared. [Example:
A constrained member function can be defined out of line:
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>
— end example]
特别注意 (non-normative) 文本的最后一个示例。
因此,Clang 拒绝是正确的,而 GCC 接受第一个程序作为 out-of-line 定义是错误的
template<typename Container> void Foo<Container>::func() {}
不匹配Foo<Container>
中的任何函数。
(我还没有找到一个公开的 GCC 错误报告)
应该为 GCC 提交错误,因为它接受代码,即使 class 之外的成员声明没有等效的 template-head。
[temp.class]
3 When a member function, a member class, a member enumeration, a static data member or a member template of a class template is defined outside of the class template definition, the member definition is defined as a template definition in which the template-head is equivalent to that of the class template ([temp.over.link]).
[temp.over.link]
6 Two template-heads are equivalent if their template-parameter-lists have the same length, corresponding template-parameters are equivalent and are both declared with type-constraints that are equivalent if either template-parameter is declared with a type-constraint, and if either template-head has a requires-clause, they both have requires-clauses and the corresponding constraint-expressions are equivalent.
templates-heads 的等价要求两者都有一个等价的 requires 子句。省略它完全破坏了等价性。