Цель этого ограничения состоит в том, чтобы усложнить ошибку, приводящую к неудовлетворительным или всегда удовлетворяемым понятиям, например:
template<class T> concept C1 = sizeof(T); // Oops, I meant to write sizeof(T) >= 2
Если sizeof(T)
неявно преобразовать в bool
C
будет удовлетворено всеми законченными типами объектов.На практике вы можете просто принудительно преобразовать выражение в bool
, если вы действительно этого хотите:
template<class T> concept C2 = (bool)sizeof(T); // I did *not* mean to write sizeof(T) >= 2
Обратите внимание, что концепции не удовлетворяются, когда подстановка создает недопустимое выражение (https://godbolt.org/z/xMHoJ0):
template<class T> concept C3 = (bool)T::value;
static_assert(C3<std::true_type>);
static_assert(!C3<int>);
или тип (https://godbolt.org/z/tnreG0):
template<class T> concept C4 = C3<typename T::type>;
static_assert(C4<std::is_same<int, int>>);
static_assert(!C4<int>);
, так что «требующие-пункты не делают SFINAE!» Точно не характеризует ситуацию.
Полагаю, я должен указатьИз других возможных ошибок - атомные выражения ограничений должны быть константными выражениями. Если подстановка в выражение ограничения создает неконстантное выражение, программа некорректна (https://godbolt.org/z/LQA1XQ):
template<class T> concept C5 = T::f();
struct S1 {
static constexpr bool f() { return true; }
};
struct S2 {
static constexpr bool f() { return false; }
};
struct S3 {
static bool f() { return true; }
};
static_assert(!C5<void>); // Invalid expression: SFINAE and concept is not satisfied
static_assert(!C5<int>); // Ditto
static_assert(C5<S1>); // Constant expression that evaluates to true
static_assert(!C5<S2>); // Constant expression that evaluates to false
static_assert(C5<S3>); // Ill-formed: not a constant expression