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
|
// RUN: %clang_cc1 -std=c++1z -verify %s
// RUN: %clang_cc1 -std=c++2a -verify %s
template<typename ...T> constexpr auto sum(T ...t) { return (... + t); }
template<typename ...T> constexpr auto product(T ...t) { return (t * ...); }
template<typename ...T> constexpr auto all(T ...t) { return (true && ... && t); }
template<typename ...T> constexpr auto dumb(T ...t) { return (false && ... && t); }
static_assert(sum(1, 2, 3, 4, 5) == 15);
static_assert(product(1, 2, 3, 4, 5) == 120);
static_assert(!all(true, true, false, true, false));
static_assert(all(true, true, true, true, true));
static_assert(!dumb(true, true, true, true, true));
struct S {
int a, b, c, d, e;
};
template<typename ...T> constexpr auto increment_all(T &...t) {
(++t, ...);
}
constexpr bool check() {
S s = { 1, 2, 3, 4, 5 };
increment_all(s.a, s.b, s.c, s.d, s.e);
return s.a == 2 && s.b == 3 && s.c == 4 && s.d == 5 && s.e == 6;
}
static_assert(check());
template<int ...N> void empty() {
static_assert((N || ...) == false);
static_assert((N && ...) == true);
(N, ...);
}
template void empty<>();
// An empty fold-expression isn't a null pointer just because it's an integer
// with value 0. (This is no longer an issue since empty pack expansions don't
// produce integers any more.)
template<int ...N> void null_ptr() {
void *p = (N || ...); // expected-error {{rvalue of type 'bool'}}
void *q = (N , ...); // expected-error {{rvalue of type 'void'}}
}
template void null_ptr<>(); // expected-note {{in instantiation of}}
template<int ...N> void bad_empty() {
(N + ...); // expected-error {{empty expansion for operator '+' with no fallback}}
(N * ...); // expected-error {{empty expansion for operator '*' with no fallback}}
(N | ...); // expected-error {{empty expansion for operator '|' with no fallback}}
(N & ...); // expected-error {{empty expansion for operator '&' with no fallback}}
(N - ...); // expected-error {{empty expansion for operator '-' with no fallback}}
(N / ...); // expected-error {{empty expansion for operator '/' with no fallback}}
(N % ...); // expected-error {{empty expansion for operator '%' with no fallback}}
(N = ...); // expected-error {{empty expansion for operator '=' with no fallback}}
}
template void bad_empty<>(); // expected-note {{in instantiation of}}
template<int ...N> void empty_with_base() {
extern int k;
(k = ... = N); // expected-warning{{unused}}
void (k = ... = N); // expected-error {{expected ')'}} expected-note {{to match}}
void ((k = ... = N));
(void) (k = ... = N);
}
template void empty_with_base<>(); // expected-note {{in instantiation of}}
template void empty_with_base<1>();
struct A {
struct B {
struct C {
struct D {
int e;
} d;
} c;
} b;
} a;
template<typename T, typename ...Ts> constexpr decltype(auto) apply(T &t, Ts ...ts) {
return (t.*....*ts);
}
static_assert(&apply(a, &A::b, &A::B::c, &A::B::C::d, &A::B::C::D::e) == &a.b.c.d.e);
#if __cplusplus > 201703L
// The <=> operator is unique among binary operators in not being a
// fold-operator.
// FIXME: This diagnostic is not great.
template<typename ...T> constexpr auto spaceship1(T ...t) { return (t <=> ...); } // expected-error {{expected expression}}
template<typename ...T> constexpr auto spaceship2(T ...t) { return (... <=> t); } // expected-error {{expected expression}}
template<typename ...T> constexpr auto spaceship3(T ...t) { return (t <=> ... <=> 0); } // expected-error {{expected expression}}
#endif
// The GNU binary conditional operator ?: is not recognized as a fold-operator.
// FIXME: Why not? This seems like it would be useful.
template<typename ...T> constexpr auto binary_conditional1(T ...t) { return (t ?: ...); } // expected-error {{expected expression}}
template<typename ...T> constexpr auto binary_conditional2(T ...t) { return (... ?: t); } // expected-error {{expected expression}}
template<typename ...T> constexpr auto binary_conditional3(T ...t) { return (t ?: ... ?: 0); } // expected-error {{expected expression}}
namespace PR41845 {
template <int I> struct Constant {};
template <int... Is> struct Sum {
template <int... Js> using type = Constant<((Is + Js) + ... + 0)>; // expected-error {{pack expansion contains parameter pack 'Js' that has a different length (1 vs. 2) from outer parameter packs}}
};
Sum<1>::type<1, 2> x; // expected-note {{instantiation of}}
}
namespace PR30738 {
namespace N {
struct S {};
}
namespace T {
void operator+(N::S, N::S) {}
template<typename ...Ts> void f() { (Ts{} + ...); }
}
void g() { T::f<N::S, N::S>(); }
template<typename T, typename ...U> auto h(U ...v) {
T operator+(T, T); // expected-note {{candidate}}
return (v + ...); // expected-error {{invalid operands}}
}
int test_h1 = h<N::S>(1, 2, 3);
N::S test_h2 = h<N::S>(N::S(), N::S(), N::S());
int test_h3 = h<struct X>(1, 2, 3);
N::S test_h4 = h<struct X>(N::S(), N::S(), N::S()); // expected-note {{instantiation of}}
}
namespace GH67395 {
template <typename>
bool f();
template <typename... T>
void g(bool = (f<T>() || ...));
}
|