xref: /llvm-project/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp (revision 36ee9fb219579e8bcac3032a042b3bddd98b3938)
19ca5c425SRichard Smith // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
23d90ae27SDouglas Gregor 
33d90ae27SDouglas Gregor // This is a collection of various template metafunctions involving
43d90ae27SDouglas Gregor // variadic templates, which are meant to exercise common use cases.
53d90ae27SDouglas Gregor template<typename T, typename U>
63d90ae27SDouglas Gregor struct is_same {
73d90ae27SDouglas Gregor   static const bool value = false;
83d90ae27SDouglas Gregor };
93d90ae27SDouglas Gregor 
103d90ae27SDouglas Gregor template<typename T>
113d90ae27SDouglas Gregor struct is_same<T, T> {
123d90ae27SDouglas Gregor   static const bool value = true;
133d90ae27SDouglas Gregor };
143d90ae27SDouglas Gregor 
153d90ae27SDouglas Gregor template<typename...> struct tuple { };
163d90ae27SDouglas Gregor template<int ...> struct int_tuple { };
17fd4344b5SDouglas Gregor template<typename T, typename U> struct pair { };
183d90ae27SDouglas Gregor 
193d90ae27SDouglas Gregor namespace Count {
203d90ae27SDouglas Gregor   template<typename Head, typename ...Tail>
213d90ae27SDouglas Gregor   struct count {
223d90ae27SDouglas Gregor     static const unsigned value = 1 + count<Tail...>::value;
233d90ae27SDouglas Gregor   };
243d90ae27SDouglas Gregor 
253d90ae27SDouglas Gregor   template<typename T>
263d90ae27SDouglas Gregor   struct count<T> {
273d90ae27SDouglas Gregor     static const unsigned value = 1;
283d90ae27SDouglas Gregor   };
293d90ae27SDouglas Gregor 
303d90ae27SDouglas Gregor   int check1[count<int>::value == 1? 1 : -1];
313d90ae27SDouglas Gregor   int check2[count<float, double>::value == 2? 1 : -1];
323d90ae27SDouglas Gregor   int check3[count<char, signed char, unsigned char>::value == 3? 1 : -1];
333d90ae27SDouglas Gregor }
343d90ae27SDouglas Gregor 
353d90ae27SDouglas Gregor namespace CountWithPackExpansion {
363d90ae27SDouglas Gregor   template<typename ...> struct count;
373d90ae27SDouglas Gregor 
383d90ae27SDouglas Gregor   template<typename Head, typename ...Tail>
393d90ae27SDouglas Gregor   struct count<Head, Tail...> {
403d90ae27SDouglas Gregor     static const unsigned value = 1 + count<Tail...>::value;
413d90ae27SDouglas Gregor   };
423d90ae27SDouglas Gregor 
433d90ae27SDouglas Gregor   template<>
443d90ae27SDouglas Gregor   struct count<> {
453d90ae27SDouglas Gregor     static const unsigned value = 0;
463d90ae27SDouglas Gregor   };
473d90ae27SDouglas Gregor 
483d90ae27SDouglas Gregor   int check0[count<>::value == 0? 1 : -1];
493d90ae27SDouglas Gregor   int check1[count<int>::value == 1? 1 : -1];
503d90ae27SDouglas Gregor   int check2[count<float, double>::value == 2? 1 : -1];
513d90ae27SDouglas Gregor   int check3[count<char, signed char, unsigned char>::value == 3? 1 : -1];
523d90ae27SDouglas Gregor }
533d90ae27SDouglas Gregor 
543d90ae27SDouglas Gregor namespace Replace {
553d90ae27SDouglas Gregor   // Simple metafunction that replaces the template arguments of
563d90ae27SDouglas Gregor   // template template parameters with 'int'.
573d90ae27SDouglas Gregor   template<typename T>
583d90ae27SDouglas Gregor   struct EverythingToInt;
593d90ae27SDouglas Gregor 
603d90ae27SDouglas Gregor   template<template<typename ...> class TT, typename T1, typename T2>
613d90ae27SDouglas Gregor   struct EverythingToInt<TT<T1, T2> > {
623d90ae27SDouglas Gregor     typedef TT<int, int> type;
633d90ae27SDouglas Gregor   };
643d90ae27SDouglas Gregor 
653d90ae27SDouglas Gregor   int check0[is_same<EverythingToInt<tuple<double, float>>::type,
663d90ae27SDouglas Gregor              tuple<int, int>>::value? 1 : -1];
673d90ae27SDouglas Gregor }
68e8e9dd62SDouglas Gregor 
69fdfd4137SDouglas Gregor namespace Math {
70e8e9dd62SDouglas Gregor   template<int ...Values>
71e8e9dd62SDouglas Gregor   struct double_values {
72e8e9dd62SDouglas Gregor     typedef int_tuple<Values*2 ...> type;
73e8e9dd62SDouglas Gregor   };
74e8e9dd62SDouglas Gregor 
75e8e9dd62SDouglas Gregor   int check0[is_same<double_values<1, 2, -3>::type,
76e8e9dd62SDouglas Gregor                      int_tuple<2, 4, -6>>::value? 1 : -1];
77e8e9dd62SDouglas Gregor 
78e8e9dd62SDouglas Gregor   template<int ...Values>
79e8e9dd62SDouglas Gregor   struct square {
80e8e9dd62SDouglas Gregor     typedef int_tuple<(Values*Values)...> type;
81e8e9dd62SDouglas Gregor   };
82e8e9dd62SDouglas Gregor 
83e8e9dd62SDouglas Gregor   int check1[is_same<square<1, 2, -3>::type,
84e8e9dd62SDouglas Gregor                      int_tuple<1, 4, 9>>::value? 1 : -1];
85e8e9dd62SDouglas Gregor 
86e8e9dd62SDouglas Gregor   template<typename IntTuple> struct square_tuple;
87e8e9dd62SDouglas Gregor 
88e8e9dd62SDouglas Gregor   template<int ...Values>
89e8e9dd62SDouglas Gregor   struct square_tuple<int_tuple<Values...>> {
90e8e9dd62SDouglas Gregor     typedef int_tuple<(Values*Values)...> type;
91e8e9dd62SDouglas Gregor   };
92e8e9dd62SDouglas Gregor 
93e8e9dd62SDouglas Gregor   int check2[is_same<square_tuple<int_tuple<1, 2, -3> >::type,
94e8e9dd62SDouglas Gregor                      int_tuple<1, 4, 9>>::value? 1 : -1];
95fdfd4137SDouglas Gregor 
96fdfd4137SDouglas Gregor   template<int ...Values> struct sum;
97fdfd4137SDouglas Gregor 
98fdfd4137SDouglas Gregor   template<int First, int ...Rest>
99fdfd4137SDouglas Gregor   struct sum<First, Rest...> {
100fdfd4137SDouglas Gregor     static const int value = First + sum<Rest...>::value;
101fdfd4137SDouglas Gregor   };
102fdfd4137SDouglas Gregor 
103fdfd4137SDouglas Gregor   template<>
104fdfd4137SDouglas Gregor   struct sum<> {
105fdfd4137SDouglas Gregor     static const int value = 0;
106fdfd4137SDouglas Gregor   };
107fdfd4137SDouglas Gregor 
108fdfd4137SDouglas Gregor   int check3[sum<1, 2, 3, 4, 5>::value == 15? 1 : -1];
1097ec835f3SDouglas Gregor 
1107ec835f3SDouglas Gregor   template<int ... Values>
1117ec835f3SDouglas Gregor   struct lazy_sum {
operator ()Math::lazy_sum1127ec835f3SDouglas Gregor     int operator()() {
1137ec835f3SDouglas Gregor       return sum<Values...>::value;
1147ec835f3SDouglas Gregor     }
1157ec835f3SDouglas Gregor   };
1167ec835f3SDouglas Gregor 
f()1177ec835f3SDouglas Gregor   void f() {
1187ec835f3SDouglas Gregor     lazy_sum<1, 2, 3, 4, 5>()();
1197ec835f3SDouglas Gregor   }
120e8e9dd62SDouglas Gregor }
121e8e9dd62SDouglas Gregor 
12251bc5719SDouglas Gregor namespace ListMath {
12351bc5719SDouglas Gregor   template<typename T, T ... V> struct add;
12451bc5719SDouglas Gregor 
12551bc5719SDouglas Gregor   template<typename T, T i, T ... V>
12651bc5719SDouglas Gregor   struct add<T, i, V...> {
12751bc5719SDouglas Gregor     static const T value = i + add<T, V...>::value;
12851bc5719SDouglas Gregor   };
12951bc5719SDouglas Gregor 
13051bc5719SDouglas Gregor   template<typename T>
13151bc5719SDouglas Gregor   struct add<T> {
13251bc5719SDouglas Gregor     static const T value = T();
13351bc5719SDouglas Gregor   };
13451bc5719SDouglas Gregor 
13551bc5719SDouglas Gregor   template<typename T, T ... V>
13651bc5719SDouglas Gregor   struct List {
13751bc5719SDouglas Gregor     struct sum {
13851bc5719SDouglas Gregor       static const T value = add<T, V...>::value;
13951bc5719SDouglas Gregor     };
14051bc5719SDouglas Gregor   };
14151bc5719SDouglas Gregor 
14251bc5719SDouglas Gregor   template<int ... V>
14351bc5719SDouglas Gregor   struct ListI : public List<int, V...> {
14451bc5719SDouglas Gregor   };
14551bc5719SDouglas Gregor 
14651bc5719SDouglas Gregor   int check0[ListI<1, 2, 3>::sum::value == 6? 1 : -1];
14751bc5719SDouglas Gregor }
14851bc5719SDouglas Gregor 
149e8e9dd62SDouglas Gregor namespace Indices {
150e8e9dd62SDouglas Gregor   template<unsigned I, unsigned N, typename IntTuple>
151e8e9dd62SDouglas Gregor   struct build_indices_impl;
152e8e9dd62SDouglas Gregor 
153e8e9dd62SDouglas Gregor   template<unsigned I, unsigned N, int ...Indices>
154e8e9dd62SDouglas Gregor   struct build_indices_impl<I, N, int_tuple<Indices...> >
155e8e9dd62SDouglas Gregor     : build_indices_impl<I+1, N, int_tuple<Indices..., I> > {
156e8e9dd62SDouglas Gregor   };
157e8e9dd62SDouglas Gregor 
158e8e9dd62SDouglas Gregor   template<unsigned N, int ...Indices>
159e8e9dd62SDouglas Gregor   struct build_indices_impl<N, N, int_tuple<Indices...> > {
160e8e9dd62SDouglas Gregor     typedef int_tuple<Indices...> type;
161e8e9dd62SDouglas Gregor   };
162e8e9dd62SDouglas Gregor 
163e8e9dd62SDouglas Gregor   template<unsigned N>
164e8e9dd62SDouglas Gregor   struct build_indices : build_indices_impl<0, N, int_tuple<> > { };
165e8e9dd62SDouglas Gregor 
166e8e9dd62SDouglas Gregor   int check0[is_same<build_indices<5>::type,
167e8e9dd62SDouglas Gregor                      int_tuple<0, 1, 2, 3, 4>>::value? 1 : -1];
168e8e9dd62SDouglas Gregor }
169f550077eSDouglas Gregor 
170f550077eSDouglas Gregor namespace TemplateTemplateApply {
171f550077eSDouglas Gregor   template<typename T, template<class> class ...Meta>
172f550077eSDouglas Gregor   struct apply_each {
173f550077eSDouglas Gregor     typedef tuple<typename Meta<T>::type...> type;
174f550077eSDouglas Gregor   };
175f550077eSDouglas Gregor 
176f550077eSDouglas Gregor   template<typename T>
177f550077eSDouglas Gregor   struct add_reference {
178f550077eSDouglas Gregor     typedef T& type;
179f550077eSDouglas Gregor   };
180f550077eSDouglas Gregor 
181f550077eSDouglas Gregor   template<typename T>
182f550077eSDouglas Gregor   struct add_pointer {
183f550077eSDouglas Gregor     typedef T* type;
184f550077eSDouglas Gregor   };
185f550077eSDouglas Gregor 
186f550077eSDouglas Gregor   template<typename T>
187f550077eSDouglas Gregor   struct add_const {
188f550077eSDouglas Gregor     typedef const T type;
189f550077eSDouglas Gregor   };
190f550077eSDouglas Gregor 
191f550077eSDouglas Gregor   int check0[is_same<apply_each<int,
192f550077eSDouglas Gregor                                 add_reference, add_pointer, add_const>::type,
193f550077eSDouglas Gregor                      tuple<int&, int*, int const>>::value? 1 : -1];
194e4ff4b56SDouglas Gregor 
195e4ff4b56SDouglas Gregor   template<typename T, template<class> class ...Meta>
196e4ff4b56SDouglas Gregor   struct apply_each_indirect {
197e4ff4b56SDouglas Gregor     typedef typename apply_each<T, Meta...>::type type;
198e4ff4b56SDouglas Gregor   };
199e4ff4b56SDouglas Gregor 
200e4ff4b56SDouglas Gregor   int check1[is_same<apply_each_indirect<int, add_reference, add_pointer,
201e4ff4b56SDouglas Gregor                                          add_const>::type,
202e4ff4b56SDouglas Gregor                      tuple<int&, int*, int const>>::value? 1 : -1];
203e4ff4b56SDouglas Gregor 
204e4ff4b56SDouglas Gregor   template<typename T, typename ...Meta>
205e4ff4b56SDouglas Gregor   struct apply_each_nested {
206e4ff4b56SDouglas Gregor     typedef typename apply_each<T, Meta::template apply...>::type type;
207e4ff4b56SDouglas Gregor   };
208e4ff4b56SDouglas Gregor 
209e4ff4b56SDouglas Gregor   struct add_reference_meta {
210e4ff4b56SDouglas Gregor     template<typename T>
211e4ff4b56SDouglas Gregor     struct apply {
212e4ff4b56SDouglas Gregor       typedef T& type;
213e4ff4b56SDouglas Gregor     };
214e4ff4b56SDouglas Gregor   };
215e4ff4b56SDouglas Gregor 
216e4ff4b56SDouglas Gregor   struct add_pointer_meta {
217e4ff4b56SDouglas Gregor     template<typename T>
218e4ff4b56SDouglas Gregor     struct apply {
219e4ff4b56SDouglas Gregor       typedef T* type;
220e4ff4b56SDouglas Gregor     };
221e4ff4b56SDouglas Gregor   };
222e4ff4b56SDouglas Gregor 
223e4ff4b56SDouglas Gregor   struct add_const_meta {
224e4ff4b56SDouglas Gregor     template<typename T>
225e4ff4b56SDouglas Gregor     struct apply {
226e4ff4b56SDouglas Gregor       typedef const T type;
227e4ff4b56SDouglas Gregor     };
228e4ff4b56SDouglas Gregor   };
229e4ff4b56SDouglas Gregor 
230e4ff4b56SDouglas Gregor   int check2[is_same<apply_each_nested<int, add_reference_meta,
231e4ff4b56SDouglas Gregor                                        add_pointer_meta, add_const_meta>::type,
232e4ff4b56SDouglas Gregor                      tuple<int&, int*, int const>>::value? 1 : -1];
233e4ff4b56SDouglas Gregor 
234f550077eSDouglas Gregor }
2355499af4eSDouglas Gregor 
2365499af4eSDouglas Gregor namespace FunctionTypes {
2375499af4eSDouglas Gregor   template<typename FunctionType>
2385499af4eSDouglas Gregor   struct Arity;
2395499af4eSDouglas Gregor 
2405499af4eSDouglas Gregor   template<typename R, typename ...Types>
2415499af4eSDouglas Gregor   struct Arity<R(Types...)> {
2425499af4eSDouglas Gregor     static const unsigned value = sizeof...(Types);
2435499af4eSDouglas Gregor   };
2445499af4eSDouglas Gregor 
2455499af4eSDouglas Gregor   template<typename R, typename ...Types>
246*36ee9fb2SRichard Smith   struct Arity<R(Types......)> { // expected-warning {{varargs}} expected-note {{pack}} expected-note {{insert ','}}
2475499af4eSDouglas Gregor     static const unsigned value = sizeof...(Types);
2485499af4eSDouglas Gregor   };
2495499af4eSDouglas Gregor 
2505499af4eSDouglas Gregor   template<typename R, typename T1, typename T2, typename T3, typename T4>
2515499af4eSDouglas Gregor   struct Arity<R(T1, T2, T3, T4)>; // expected-note{{template is declared here}}
2525499af4eSDouglas Gregor 
2535499af4eSDouglas Gregor   int check0[Arity<int()>::value == 0? 1 : -1];
2545499af4eSDouglas Gregor   int check1[Arity<int(float, double)>::value == 2? 1 : -1];
2555499af4eSDouglas Gregor   int check2[Arity<int(float...)>::value == 1? 1 : -1];
2565499af4eSDouglas Gregor   int check3[Arity<int(float, double, long double...)>::value == 3? 1 : -1];
2575499af4eSDouglas Gregor   Arity<int(float, double, long double, char)> check4; // expected-error{{implicit instantiation of undefined template 'FunctionTypes::Arity<int (float, double, long double, char)>'}}
2585499af4eSDouglas Gregor }
259fd4344b5SDouglas Gregor 
260fd4344b5SDouglas Gregor namespace SuperReplace {
261fd4344b5SDouglas Gregor   template<typename T>
262fd4344b5SDouglas Gregor   struct replace_with_int {
263fd4344b5SDouglas Gregor     typedef int type;
264fd4344b5SDouglas Gregor   };
265fd4344b5SDouglas Gregor 
266fd4344b5SDouglas Gregor   template<template<typename ...> class TT, typename ...Types>
267fd4344b5SDouglas Gregor   struct replace_with_int<TT<Types...>> {
268fd4344b5SDouglas Gregor     typedef TT<typename replace_with_int<Types>::type...> type;
269fd4344b5SDouglas Gregor   };
270fd4344b5SDouglas Gregor 
271fd4344b5SDouglas Gregor   int check0[is_same<replace_with_int<pair<tuple<float, double, short>,
272fd4344b5SDouglas Gregor                                            pair<char, unsigned char>>>::type,
273fd4344b5SDouglas Gregor                      pair<tuple<int, int, int>, pair<int, int>>>::value? 1 : -1];
274fd4344b5SDouglas Gregor }
275