Ну, что это на самом деле означает:
template <typename T, typename U>
concept equality_comparable = requires(T a, U b) {
{ a == b } -> bool;
{ a != b } -> bool;
};
Означает ли это, что a == b
должен иметь тип точно bool
, или это означает, что если вы распадаете тип, который вы get bool
(то есть const bool
или bool&
в порядке), или это означает, что преобразуется в bool
(т.е. std::true_type
в порядке)? Я не думаю, что это вообще ясно из синтаксиса - и любой из этих трех может быть осмысленно желаемым для конкретной концепции (как P1452 указывает, в то время, отношение Same<T>
к ConvertibleTo<T>
в понятиях было 40-14).
Далее в статье указывается, что в Концепции TS, где существовал -> Type
, мы также имели возможность написать что-то вроде vector<Concept>
... или -> vector<Concept>
в качестве требования. Это тип, но он будет очень трудно вести себя с семантикой decltype(())
, принятой нами в P1084 .
По сути, я не думаю, что на самом деле «отлично читаемый» фрагмент - это несколько возможных значений для этого синтаксиса, каждый из которых может иметь желаемое значение в зависимости от контекста. И наиболее часто используемый в то время (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>
.
Это не строго связано с оригиналом вопрос, но мне просто интересно добавить еще какой-нибудь цвет.