Неявные варианты выражения require должны соответствовать следующим требованиям:
Требует выражения, которое использует выражение, которое не является модификацией для некоторого постоянного операнда lvalue, также неявно требует дополнительных вариантов этого выражения, которые принимают непостоянное lvalue или (возможно, постоянное) rvalue для данного операнда, если такой вариант выражения не требуется явно. с различной семантикой.
Эти неявные варианты выражений должны соответствовать тем же семантическим требованиям, что и объявленное выражение. Степень, в которой реализация проверяет синтаксис вариантов, не указана.
template<class T> concept C = requires(T a, T b, const T c, const T d) { c == d; // expression #1: does not modify the operands a = std::move(b); // expression #2: modifies both operands a = c; // expression #3: modifies the left operand `a` }; // Expression #1 implicitly requires additional expression variations that // meet the requirements for c == d (including non-modification), // as if the following expressions had been declared as well: // ------ const == const ------- ------ const == non-const --- // c == b; // c == std::move(d); c == std::move(b); // std::move(c) == d; std::move(c) == b; // std::move(c) == std::move(d); std::move(c) == std::move(b); // -- non-const == const ------- -- non-const == non-const --- // a == d; a == b; // a == std::move(d); a == std::move(b); // std::move(a) == d; std::move(a) == b; // std::move(a) == std::move(d); std::move(a) == std::move(b); // Expression #3 implicitly requires additional expression variations that // meet the requirements for a = c // (including non-modification of the second operand), // as if the expressions a = b (non-constant lvalue variation) // and a = std::move(c) (const rvalue variation) had been declared. // Note: Since expression #2 already requires the non-constant rvalue variation // (a == std::move(b)) explicitly, expression #3 does not implicitly require it anymore. // The type T meets the explicitly stated syntactic requirements of // concept C above, but does not meet the additional implicit requirements // (i.e., T satisfies but does not model C): // a program requires C<T> is ill-formed (no diagnostic required). struct T { bool operator==(const T&) const { return true; } bool operator==(T&) = delete; };
Но, похоже, ни один из последних компиляторов не следует этому правилу (https://godbolt.org/z/84rK7rGTb - C<T>
должно оцениваться как false). Я что-то пропустил?
В случае сомнений смотрите непосредственно стандарт: https://eel.is/c++draft/concepts.equality#8
См. https://eel.is/c++draft/concepts.equality#8 акцент мой:
[Пример 4: Следующий тип
T
отвечает явно указанным синтаксическим требованиям понятияC
выше, но не соответствует дополнительным неявным требованиям:struct T { bool operator==(const T&) const { return true; } bool operator==(T&) = delete; };
T
не соответствует неявным требованиямC
, поэтомуT
удовлетворяет, но не моделируетC
. Поскольку реализациям не требуется проверять синтаксис неявных требований, неясно, диагностируется ли реализация как неправильно сформированная программа, требующаяC<T>
. — конец примера]
Так что никакой диагностики не требуется.
Цитирую вашу цитату:
Степень, в которой реализация проверяет синтаксис вариантов, не указана.
...
// a program requires C<T> is ill-formed (no diagnostic required).
Компилятору не требуется проверять при проверке C<T>
, что для T a, b
a == b
разрешено.
Существует разница между удовлетворением концепции и моделированием концепции. Удовлетворение концепции C
T
определяется тем, оценивается ли C<T>
до true
. Обратите внимание, что правила вычисления выражения requires
ничего не говорят о проверке неявных вариаций выражения. На самом деле было бы неправильно, если бы компилятор оценивал от C<T>
до false
в вашем примере.
Моделирование концепции — это понятие, которое, как правило, не может быть проверено компилятором. Концепция моделируется, когда она удовлетворяется и тип ведет себя так, как «должен». Например, следующий тип
struct U { bool operator==(U const&) const { return false; } };
удовлетворяет std::equality_comparable
(поскольку a == b
, a != b
и т. д. хорошо сформированы), но не моделирует std::equality_comparable
, поскольку ==
не является разумным понятием равенства (оно не рефлексивно). Неявные вариации выражений, требуемые концепцией, являются частью того, что означает моделирование концепции, но не тем, что означает ее удовлетворение. Они выходят за рамки того, что требуется проверить компилятору.
Если компилятор реализует проверку того, моделируют ли типы концепцию, это (опять же) не должно проявляться как концепция, которая фактически оценивается как false
. Вместо этого он может выдать предупреждение или ошибку, когда заметит, что вернулась оценка концепции true
, но концепция на самом деле не смоделирована. Я не уверен, что какой-либо компилятор делает это для какой-либо концепции на практике.
Вы имеете в виду, что оценка C<T>
должна быть true
? Стандарт, упомянутый Джародом, говорит, что он не указан.
@김선달 Нет, там написано не это. Там говорится, что программа, требующая C<T>
, может быть диагностирована как неправильно сформированная. Плохо сформированная программа не подразумевает C<T>
вычисления для false
. Если есть диагноз, он должен быть примерно таким: «C<T>
оценивается как true
, но T
не моделируется C
из-за несоответствия неявным требованиям вариации выражения». Опять же, нет возможности учитывать неявные вариации выражений при вычислении выражения requires
.
Цитируем стандарт: неопределенное поведение возникает, когда ограничение удовлетворяется, но не моделируется, согласно eel.is/c++draft/res.on.requirements . Когда концепция используется в логическом выражении, она оценивается путем проверки того, удовлетворяется ли концепция, согласно eel.is/c++draft/temp.names#9 . Удовлетворение однозначное: оно сводится к подстановке параметров шаблона в выражение, определяющее концепцию, согласно eel.is/c++draft/temp.constr.constr#temp.constr.atomic-3. Если тип T
удовлетворяет концепции C
, но не моделирует ее, это означает, что C<T>
оценивается как true
.
Теперь я понимаю. Спасибо!
«Степень, в которой реализация проверяет синтаксис вариантов, не указана».