compound-requirement.cpp
7.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
static_assert(requires { { 0 }; });
static_assert(requires { { "aaaa" }; });
static_assert(requires { { (0).da }; }); // expected-error{{member reference base type 'int' is not a structure or union}}
void foo() {}
static_assert(requires { { foo() }; });
// Substitution failure in expression
struct A {};
struct B {
B operator+(const B &other) const { return other; }
};
struct C {
C operator+(C &other) const { return other; }
};
template<typename T> requires requires (T a, const T& b) { { a + b }; } // expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('A' and 'const A')}} expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('C' and 'const C')}}
struct r1 {};
using r1i1 = r1<int>;
using r1i2 = r1<A>; // expected-error{{constraints not satisfied for class template 'r1' [with T = A]}}
using r1i3 = r1<B>;
using r1i4 = r1<C>; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}}
struct D { void foo() {} };
template<typename T> requires requires (T a) { { a.foo() }; } // expected-note{{because 'a.foo()' would be invalid: no member named 'foo' in 'A'}} expected-note{{because 'a.foo()' would be invalid: member reference base type 'int' is not a structure or union}} expected-note{{because 'a.foo()' would be invalid: 'this' argument to member function 'foo' has type 'const D', but function is not marked const}}
struct r2 {};
using r2i1 = r2<int>; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}}
using r2i2 = r2<A>; // expected-error{{constraints not satisfied for class template 'r2' [with T = A]}}
using r2i3 = r2<D>;
using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}}
template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
struct r3 {};
using r3i1 = r3<int>;
using r3i2 = r3<A>;
using r3i3 = r3<A &>;
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
// Non-dependent expressions
template<typename T> requires requires (T t) { { 0 }; { "a" }; { (void)'a' }; }
struct r4 {};
using r4i1 = r4<int>;
using r4i2 = r4<int[10]>;
using r4i3 = r4<int(int)>;
// Noexcept requirement
void maythrow() { }
static_assert(!requires { { maythrow() } noexcept; });
static_assert(requires { { 1 } noexcept; });
struct E { void operator++(int) noexcept; };
struct F { void operator++(int); };
template<typename T> requires requires (T t) { { t++ } noexcept; } // expected-note{{because 't ++' may throw an exception}}
struct r5 {};
using r5i1 = r5<int>;
using r5i2 = r5<E>;
using r5i2 = r5<F>; // expected-error{{constraints not satisfied for class template 'r5' [with T = F]}}
template<typename T> requires requires (T t) { { t.foo() } noexcept; } // expected-note{{because 't.foo()' would be invalid: no member named 'foo' in 'E'}}
struct r6 {};
using r6i = r6<E>; // expected-error{{constraints not satisfied for class template 'r6' [with T = E]}}
template<typename T, typename U>
constexpr bool is_same_v = false;
template<typename T>
constexpr bool is_same_v<T, T> = true;
template<typename T, typename U>
concept Same = is_same_v<T, U>;
template<typename T>
concept Large = sizeof(T) >= 4; // expected-note{{because 'sizeof(short) >= 4' (2 >= 4) evaluated to false}}
template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'decltype(t)' (aka 'short') does not satisfy 'Large':}}
struct r7 {};
using r7i1 = r7<int>;
using r7i2 = r7<short>; // expected-error{{constraints not satisfied for class template 'r7' [with T = short]}}
template<typename T> requires requires (T t) { { t } -> Same<T>; }
struct r8 {};
using r8i1 = r8<int>;
using r8i2 = r8<short*>;
// Substitution failure in type constraint
template<typename T> requires requires (T t) { { t } -> Same<typename T::type>; } // expected-note{{because 'Same<expr-type, typename T::type>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
struct r9 {};
struct M { using type = M; };
using r9i1 = r9<M>;
using r9i2 = r9<int>; // expected-error{{constraints not satisfied for class template 'r9' [with T = int]}}
// Substitution failure in both expression and return type requirement
template<typename T> requires requires (T t) { { t.foo() } -> Same<typename T::type>; } // expected-note{{because 't.foo()' would be invalid: member reference base type 'int' is not a structure or union}}
struct r10 {};
using r10i = r10<int>; // expected-error{{constraints not satisfied for class template 'r10' [with T = int]}}
// Non-type concept in type constraint
template<int T>
concept IsEven = (T % 2) == 0;
template<typename T> requires requires (T t) { { t } -> IsEven; } // expected-error{{concept named in type constraint is not a type concept}}
struct r11 {};
// C++ [expr.prim.req.compound] Example
namespace std_example {
template<typename T> concept C1 =
requires(T x) {
{x++};
};
template<typename T, typename U> constexpr bool is_same_v = false;
template<typename T> constexpr bool is_same_v<T, T> = true;
template<typename T, typename U> concept same_as = is_same_v<T, U>;
// expected-note@-1 {{because 'is_same_v<int, int *>' evaluated to false}}
static_assert(C1<int>);
static_assert(C1<int*>);
template<C1 T> struct C1_check {};
using c1c1 = C1_check<int>;
using c1c2 = C1_check<int[10]>;
template<typename T> concept C2 =
requires(T x) {
{*x} -> same_as<typename T::inner>;
// expected-note@-1{{because type constraint 'same_as<int, typename T2::inner>' was not satisfied:}}
// expected-note@-2{{because '*x' would be invalid: indirection requires pointer operand ('int' invalid)}}
};
struct T1 {
using inner = int;
inner operator *() { return 0; }
};
struct T2 {
using inner = int *;
int operator *() { return 0; }
};
static_assert(C2<T1>);
template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}}
using c2c1 = C2_check<int>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}}
using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}}
template<typename T>
void g(T t) noexcept(sizeof(T) == 1) {}
template<typename T> concept C5 =
requires(T x) {
{g(x)} noexcept; // expected-note{{because 'g(x)' may throw an exception}}
};
static_assert(C5<char>);
template<C5 T> struct C5_check {}; // expected-note{{because 'short' does not satisfy 'C5'}}
using c5 = C5_check<short>; // expected-error{{constraints not satisfied for class template 'C5_check' [with T = short]}}
}