上次我将 C++ 概念与 GCC 和 fconcepts 标志一起使用时,以下代码段曾经起作用
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> bool;
{ a != b } -> bool;
};
Run Code Online (Sandbox Code Playgroud)
显然,情况不再如此,复合需求之后的返回类型需求现在只能包含类型约束。如果我没记错的话,这基本上意味着使用另一个概念来满足return-type-requirement。
所以完全可读和(对于 C++ 标准)短片断变成
template <typename From, typename To>
concept convertible_to = std::is_convertible_v<From, To>;
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> convertible_to<bool>;
{ a != b } -> convertible_to<bool>;
};
Run Code Online (Sandbox Code Playgroud)
当然,这甚至不是一个完整的实现,但现在让我们忽略它。有人可以向我解释为什么委员会决定改变这一点吗?我个人认为 convertible_to 概念中的“隐式使用的模板参数”非常令人恼火和令人困惑。
嗯,这实际上意味着什么:
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> bool;
{ a != b } -> bool;
};
Run Code Online (Sandbox Code Playgroud)
这是否意味着a == bmust have type exact bool,或者是否意味着如果你衰减你得到的类型bool(即const bool或没问题bool&),还是意味着可以转换为bool(即没问题std::true_type)?我不认为这是在从语法全部清除-这三个中的任何一个可以通过一个特定的概念进行有意义的期望(如P1452所指出的,在当时的比值,Same<T>以ConvertibleTo<T>在概念为40-14)。
该论文还指出,在-> Type存在的概念 TS 中,我们也有能力编写类似vector<Concept>……或-> vector<Concept>作为要求的内容。这是一种类型,但对于decltype(())我们在P1084 中采用的语义会表现得很困难。
基本上我不认为“完全可读”的片段实际上是 - 该语法有多种潜在含义,所有这些含义都可以根据上下文成为所需的含义。而当时最常用的(same_as<bool>)甚至不是我们这里想要的(convertible_to<bool>)。
我个人认为 convertible_to 概念中的“隐式使用的模板参数”非常令人恼火和令人困惑。
它在 C++ 中很新颖,但我个人发现在这些情况下它读起来非常好。看到:
{ a == b } -> convertible_to<bool>;
Run Code Online (Sandbox Code Playgroud)
只需完全按照要求读取:a == b需要是可转换为bool. 对于一元概念,它使用法非常好,因为您可以使用它们代替有些无意义的typename/class关键字:
template <range R>
void algo(R&& r);
Run Code Online (Sandbox Code Playgroud)
这与其他语言没有什么不同。例如,在 Rust 中:
fn algo<I: Iterator>(i: I)
Run Code Online (Sandbox Code Playgroud)
“隐式使用的模板参数”是如此隐含,以至于它甚至不是特征声明的一部分,它也隐含在那里:
pub trait Iterator { ... }
Run Code Online (Sandbox Code Playgroud)
因此,即使使用更长格式的语法,您也会编写,where I: Iterator而在 C++ 中您仍然会编写requires range<R>.
这与原始问题并不严格相关,但我只是觉得添加其他颜色很有趣。