Привет всем!
Может мне кто-нибудь объяснить по-простому, что за зверь —
equality preservation и какую роль он играет при определении концептов, желательно с примерами?
Например, есть концепт
regular_invocable, который определен следующим образом:
template< class F, class... Args >
concept regular_invocable = std::invocable<F, Args...>;
Говорится, что reqular_invocable отличается от просто invocable как раз вот тем самым свойством equality preservation. Хотелось бы понимать, почему это важно и как это свойство проявляется при практическом использовании.
Здравствуйте, rg45, Вы писали:
R>Может мне кто-нибудь объяснить по-простому что за зверь — equality preservation и какую роль он играет при определении концептов, желательно с примерами?
Для меня это новинка, но из сумбурного описания и примеров на cppreference я могу сделать следующий вывод.
В requires statement пишется ряд выражений.
Эти выражения либо изменяют, либо не изменяют аргументы
requires(Foo f, Bar b)
{
foo(f);
bar(b);
buz(f, b);
}
Смысл вот какой. requires сейчас может проверять только синтаксис и семантику на уровне "нашли ли подходящую функцию" и "тот ли тип мы вернули".
Поэтому во время компиляции нам наплевать, изменяются ли значения. Компилятор вообще не оперирует значениями.
(Хотя! Если мы туда присобачим какие-нибудь constexpr функции... Надо проверить!)
Но возможно, что в будущем компилятор сможет копать глубже, и делать какие-то рантаймовые проверки, вида "а вот если мы сконструировали объект, то будет ли функция над ним возвращать то или иное..."
Поэтому с самого начала оговаривается, что — в пользовательских концептах любую дичь творите, а в стандартной библиотеке неконстантные действия только в известном и узко ограниченном наборе концептов.
Здравствуйте, Кодт, Вы писали:
К>Поэтому во время компиляции нам наплевать, изменяются ли значения. Компилятор вообще не оперирует значениями.
К>(Хотя! Если мы туда присобачим какие-нибудь constexpr функции... Надо проверить!)
Ну а почему нет?
http://coliru.stacked-crooked.com/a/80f1f5a269b4f138
template <auto expected, auto f, auto...args>
concept ExpectEqual = (expected == f(args...));
template <auto expected, auto f, auto...args>
concept ExpectNotEqual = !ExpectEqual<expected, f, args...>;
constexpr size_t factorial(size_t x) { return x > 0 ? x * factorial(x - 1) : 1; }
static_assert(ExpectEqual<1, factorial, 0>);
static_assert(ExpectEqual<1, factorial, 1>);
static_assert(ExpectEqual<2, factorial, 2>);
static_assert(ExpectEqual<6, factorial, 3>);
static_assert(ExpectEqual<24, factorial, 4>);
static_assert(ExpectEqual<120, factorial, 5>);
static_assert(ExpectEqual<720, factorial, factorial(3)>);
static_assert(ExpectNotEqual<0, factorial, 0>);
static_assert(ExpectNotEqual<7, factorial, 3>);
static_assert(ExpectNotEqual<1, factorial, 1, 2, 3, 4, 5>);
Компайл-тайм юнит-тесты
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, rg45, Вы писали:
К>>>(Хотя! Если мы туда присобачим какие-нибудь constexpr функции... Надо проверить!)
R>>Ну а почему нет?
К>Ещё нет, потому что мы не втащили сюда неконстантность.
А как же
NON-CONSTANT CONSTANT-EXPRESSIONS IN C++ ?