C++ 概念复合需求和 return-type-requirements
C++ concepts compound requirements and return-type-requirements
上次我将 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 在 compound requirement 之后现在只能包含类型约束。如果我没记错的话,这基本上意味着使用另一个概念来满足 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 概念中的 "implicitly used template parameter" 非常令人恼火和困惑。
嗯,这到底是什么意思:
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
的 Concepts TS 中,我们也有能力编写类似 vector<Concept>
... 或 -> vector<Concept>
的内容作为要求。这是一种类型,但对于我们在 P1084 中采用的 decltype(())
语义来说会非常困难。
基本上我不认为 "perfectly readable" 片段实际上是 - 该语法有多种潜在含义,所有这些都可以是所需的含义,具体取决于上下文。而当时最常用的(same_as<bool>
)甚至不是我们这里想要的那个(convertible_to<bool>
)。
Personally I find that "implicitly used template parameter" in the convertible_to concept extremely irritating and confusing.
它在 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)
那里的 "implicitly used template parameter" 是如此隐含以至于它甚至不是 trait declaration 的一部分,它也隐含在那里:
pub trait Iterator { ... }
因此,即使使用更长格式的语法,您仍会编写 where I: Iterator
而在 C++ 中,您仍然会编写 requires range<R>
.
这与原始问题没有严格的关系,但我只是觉得添加一些其他颜色很有趣。
上次我将 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 在 compound requirement 之后现在只能包含类型约束。如果我没记错的话,这基本上意味着使用另一个概念来满足 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 概念中的 "implicitly used template parameter" 非常令人恼火和困惑。
嗯,这到底是什么意思:
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
的 Concepts TS 中,我们也有能力编写类似 vector<Concept>
... 或 -> vector<Concept>
的内容作为要求。这是一种类型,但对于我们在 P1084 中采用的 decltype(())
语义来说会非常困难。
基本上我不认为 "perfectly readable" 片段实际上是 - 该语法有多种潜在含义,所有这些都可以是所需的含义,具体取决于上下文。而当时最常用的(same_as<bool>
)甚至不是我们这里想要的那个(convertible_to<bool>
)。
Personally I find that "implicitly used template parameter" in the convertible_to concept extremely irritating and confusing.
它在 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)
那里的 "implicitly used template parameter" 是如此隐含以至于它甚至不是 trait declaration 的一部分,它也隐含在那里:
pub trait Iterator { ... }
因此,即使使用更长格式的语法,您仍会编写 where I: Iterator
而在 C++ 中,您仍然会编写 requires range<R>
.
这与原始问题没有严格的关系,但我只是觉得添加一些其他颜色很有趣。