形式化具有条件要求的概念
Formalizing a concept with conditional requirements
C++20 中概念的一个好处是,此功能允许并鼓励程序员指定(使用 C++ 语言本身)有关其接口的信息,这些信息以前必须在仅供人类使用的文档中,在像英语这样的自然语言。
例如,我有一个泛型算法,我们称它为template<int N, template<int> class X> void foo(X<N>)
。我的foo()
解决了数值域的某个问题。我关于如何使用 foo()
的纯英文文档是这样说的:“foo()
接受 class X<N>
的参数,foo 的用户必须实现它。class X<N>
有一个整数模板参数 N 描述它有多少行。Class X<N>
提供运算符 [] 来访问行的元素。X<N>
也提供了一个成员函数reduce(),除非N=1,在这种情况下reduction没有意义,因为只有一行。"
我将如何构思这个?我的第一种方法是:
template<class T>
concept Fooable = requires(T x, int i) {
x[i];
}
但这并没有正式化 reduce() 要求。
如果我只有一个(正式的)概念,那么我不能在 requires 表达式中包含 x.reduce() 因为一些 Fooable classes,即 N=1 的那些,不并且无法实现 reduce() 方法。
我希望我的 requires 表达式包含类似 if constepxr(T::N > 1) x.reduce();
的内容,但是 if
是控制流语句而不是表达式,因此不能在 requires 表达式中。
问题:我如何使用 C++20 概念将此合约形式化?
好吧,这出奇地简单。
#include <concepts>
#include <cstddef>
#include <type_traits>
template<int N, template<int> class X>
concept Fooable =
requires(X<N> a, int i) { a[i]; } &&
(
N == 1 ||
requires(X<N> a) { a.reduce(); }
);
template<int N, template<int> class X>
requires Fooable<N, X>
void foo(X<N>) {}
template<int N>
struct Myx1 {
int operator[](int) { return 0; };
};
template<int N>
struct Myx2 {
int operator[](int) { return 0; }
int reduce() { return 0; }
};
int main() {
foo(Myx1<1>{});
foo(Myx1<2>{}); // error - no reduce() and N != 1
foo(Myx2<2>{});
}
概念中的 ||
运算符是 short-circuiting,就像普通运算符一样,因此 N == 1 || something
按预期工作。
C++20 中概念的一个好处是,此功能允许并鼓励程序员指定(使用 C++ 语言本身)有关其接口的信息,这些信息以前必须在仅供人类使用的文档中,在像英语这样的自然语言。
例如,我有一个泛型算法,我们称它为template<int N, template<int> class X> void foo(X<N>)
。我的foo()
解决了数值域的某个问题。我关于如何使用 foo()
的纯英文文档是这样说的:“foo()
接受 class X<N>
的参数,foo 的用户必须实现它。class X<N>
有一个整数模板参数 N 描述它有多少行。Class X<N>
提供运算符 [] 来访问行的元素。X<N>
也提供了一个成员函数reduce(),除非N=1,在这种情况下reduction没有意义,因为只有一行。"
我将如何构思这个?我的第一种方法是:
template<class T>
concept Fooable = requires(T x, int i) {
x[i];
}
但这并没有正式化 reduce() 要求。
如果我只有一个(正式的)概念,那么我不能在 requires 表达式中包含 x.reduce() 因为一些 Fooable classes,即 N=1 的那些,不并且无法实现 reduce() 方法。
我希望我的 requires 表达式包含类似 if constepxr(T::N > 1) x.reduce();
的内容,但是 if
是控制流语句而不是表达式,因此不能在 requires 表达式中。
问题:我如何使用 C++20 概念将此合约形式化?
好吧,这出奇地简单。
#include <concepts>
#include <cstddef>
#include <type_traits>
template<int N, template<int> class X>
concept Fooable =
requires(X<N> a, int i) { a[i]; } &&
(
N == 1 ||
requires(X<N> a) { a.reduce(); }
);
template<int N, template<int> class X>
requires Fooable<N, X>
void foo(X<N>) {}
template<int N>
struct Myx1 {
int operator[](int) { return 0; };
};
template<int N>
struct Myx2 {
int operator[](int) { return 0; }
int reduce() { return 0; }
};
int main() {
foo(Myx1<1>{});
foo(Myx1<2>{}); // error - no reduce() and N != 1
foo(Myx2<2>{});
}
概念中的 ||
运算符是 short-circuiting,就像普通运算符一样,因此 N == 1 || something
按预期工作。