我上一次在GCC中使用C ++概念,并且fconcepts标记了下面的代码片段
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> bool;
{ a != b } -> bool;
};
显然情况已不再如此,复合要求之后的返回类型要求现在只能包含类型约束。如果我没记错的话,这基本上意味着要使用另一个概念来满足 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>;
};
当然,这甚至不是完整的实现,但现在让我们忽略它。有人可以向我解释为什么委员会决定改变这一点吗?我个人发现,convertible_to概念中的“隐式使用的模板参数”非常令人讨厌和混乱。
答案 0 :(得分:8)
嗯,这实际上是什么意思:
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> bool;
{ a != b } -> bool;
};
这是否意味着a == b
必须具有确切的类型 bool
,还是意味着如果您衰减了类型,则会得到bool
(即{{1} }或const bool
可以),还是意味着可以转换为bool&
(即bool
可以)?我认为从语法上看这还不是很清楚-特定概念可能会有意义地期望这三个中的任何一个(正如P1452当时指出的std::true_type
与Same<T>
的概念是40-14)。
该论文还继续指出,在存在ConvertibleTo<T>
的Concepts TS中,我们还能够将-> Type
...或vector<Concept>
这样的东西写为需求。这是一种类型,但是使用我们在P1084中采用的-> vector<Concept>
语义很难表现。
基本上,我认为“完全可读”的代码段实际上不是-该语法有多种潜在含义,根据上下文,所有这些含义都可能是所需的含义。当时最常用的一个(decltype(())
甚至都不是我们想要的一个(same_as<bool>
)。
我个人认为,convertible_to概念中的“隐式使用的模板参数”非常烦人和令人困惑。
它在C ++中是新颖的,但我个人发现在这些情况下,它的读法非常好。看到:
convertible_to<bool>
只需按照要求进行读取:{ a == b } -> convertible_to<bool>;
必须是可转换为a == b
的有效表达式。对于一元概念,由于您可以使用它们代替有些无意义的bool
/ typename
关键字,因此它的用法非常好:
class
与其他语言没什么不同。例如,在Rust中:
template <range R>
void algo(R&& r);
“隐式使用的模板参数”是如此隐式,以至于它甚至都不是trait declaration的一部分,它也隐式存在:
fn algo<I: Iterator>(i: I)
因此,即使使用更长格式的语法,您也将编写pub trait Iterator { ... }
,而在C ++中,您仍将编写where I: Iterator
。
这与原始问题并不严格相关,但是我发现添加其他颜色很有趣。