首页 > 解决方案 > C++ 概念复合要求和返回类型要求

问题描述

上次我将 C++ 概念与 GCC 和 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 概念中的“隐式使用的模板参数”非常令人恼火和混乱。

标签: c++c++20

解决方案


好吧,这实际上意味着什么:

template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
  { a == b } -> bool;
  { a != b } -> bool;
};

这是否意味着a == b必须完全 bool具有类型,或者是否意味着如果你衰减你得到的类型bool(即const bool或者bool&是好的),或者它是否意味着可转换为bool(即std::true_type是好的)?我认为从语法上看一点都不清楚——这三个中的任何一个都可能是一个特定概念有意义的需要(正如P1452指出的那样,当时概念中的比率Same<T>ConvertibleTo<T>40-14)。

该论文还继续指出,在-> Type已有的概念 TS 中,我们也有能力编写类似vector<Concept>......或-> vector<Concept>作为要求的东西。那是一种类型,但在使用我们在P1084decltype(())中采用的语义时会表现得非常困难。

基本上我不认为“完全可读”的片段实际上是 - 该语法有多种潜在含义,所有这些都可能是取决于上下文的期望含义。而当时最常用的(same_as<bool>)甚至不是我们想要的(convertible_to<bool>)。


我个人发现 convertible_to 概念中的“隐式使用的模板参数”非常令人恼火和混乱。

它在 C++ 中很新颖,但我个人发现它在这些情况下读起来非常好。看到:

{ a == b } -> convertible_to<bool>;

完全按照要求读取:a == b需要是可转换为的有效表达式bool。对于一元概念,它使用法非常好,因为您可以使用它们来代替有些无意义的typename/class关键字:

template <range R>
void algo(R&& r);

这与其他语言没有什么不同。比如,在 Rust 中:

fn algo<I: Iterator>(i: I)

那里的“隐式使用的模板参数”是如此隐含,以至于它甚至不是特征声明的一部分,它也是隐含的:

pub trait Iterator { ... }

因此,即使使用较长形式的语法,您也会编写where I: Iterator,而在 C++ 中您仍然会编写requires range<R>.

这与原始问题并不严格相关,但我只是觉得添加一些其他颜色很有趣。


推荐阅读