具有多个模板参数的概念

Concept with multiple template arguments

我正在尝试使用 C++20 概念,开始熟悉它们。 我对简单的概念感到很舒服,例如使用标准概念 movable 我可以写这样的东西(在所有示例中我想我是 using namespace std 并且我包括 <concepts> 和任何其他header 需要):

template<movable T>
int foo (T obj);

并确保在调用此函数时可以移动传递的 object obj。 我什至可以写成更长的形式:

template<typename T>
requires movable<T>
int foo (T obj);

结果会是一样的(我想)。

但是现在让我们看看另一个概念,例如same_assame_as 接受 2 个模板参数(要比较的 2 种类型),所以我可以写:

template<typename T>
requires same_as<T, string>
int bar (T obj);

现在 T 是 string。但是我怎样才能用更短的形式写呢?我试过了,我可以这样写(正如我的直觉所料):

template<same_as<string> T>
int bar (T obj);

但是这种形式背后的正式规则是什么?

函数模板参数的名称 (T)是否作为概念模板的第一个参数输入?或者也许是最后一次?我不知道,关于这个主题的信息很少。我的意思是,在这个例子中它是无关紧要的,因为 same_as<A, B> is semantically equivalentsame_as<B, A>,但在某些情况下顺序很重要。


我知道有类似标题的问题,例如,但它问的是不同的东西。

这些是我试图从中获取信息但失败的资源:cppReference, cppModernes, open-std (I browsed years 2018, 2019 and 2020) and this post

But what is the formal rule behind this form?

[temp.param]/4:

中描述了规则(您正确猜中的方式)

A type-constraint Q that designates a concept C can be used to constrain a contextually-determined type or template type parameter pack T with a constraint-expression E defined as follows. If Q is of the form C<A1, ⋯, An>, then let E′ be C<T, A1, ⋯, An>. Otherwise, let E′ be C<T>. If T is not a pack, then E is E′, otherwise E is (E′ && ...). This constraint-expression E is called the immediately-declared constraint of Q for T. The concept designated by a type-constraint shall be a type concept ([temp.concept]).

在后续段落中有示例:

A type-parameter that starts with a type-constraint introduces the immediately-declared constraint of the type-constraint for the parameter. [ Example:

template<typename T> concept C1 = true;
template<typename... Ts> concept C2 = true;
template<typename T, typename U> concept C3 = true;

template<C1 T> struct s1;               // associates C1<T>
template<C1... T> struct s2;            // associates (C1<T> && ...)
template<C2... T> struct s3;            // associates (C2<T> && ...)
template<C3<int> T> struct s4;          // associates C3<T, int>
template<C3<int>... T> struct s5;       // associates (C3<T, int> && ...)

— end example ]

您也可以将 template <C T> 视为 template <C<> T> 的 shorthand,然后类型参数 T 总是插入概念的第一个参数。