xref: /llvm-project/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp (revision 7ec835f35b80d6b61c63d0dd2a2b9cc2956c36bb)
1 // RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
2 
3 // This is a collection of various template metafunctions involving
4 // variadic templates, which are meant to exercise common use cases.
5 template<typename T, typename U>
6 struct is_same {
7   static const bool value = false;
8 };
9 
10 template<typename T>
11 struct is_same<T, T> {
12   static const bool value = true;
13 };
14 
15 template<typename...> struct tuple { };
16 template<int ...> struct int_tuple { };
17 
18 namespace Count {
19   template<typename Head, typename ...Tail>
20   struct count {
21     static const unsigned value = 1 + count<Tail...>::value;
22   };
23 
24   template<typename T>
25   struct count<T> {
26     static const unsigned value = 1;
27   };
28 
29   int check1[count<int>::value == 1? 1 : -1];
30   int check2[count<float, double>::value == 2? 1 : -1];
31   int check3[count<char, signed char, unsigned char>::value == 3? 1 : -1];
32 }
33 
34 namespace CountWithPackExpansion {
35   template<typename ...> struct count;
36 
37   template<typename Head, typename ...Tail>
38   struct count<Head, Tail...> {
39     static const unsigned value = 1 + count<Tail...>::value;
40   };
41 
42   template<>
43   struct count<> {
44     static const unsigned value = 0;
45   };
46 
47   int check0[count<>::value == 0? 1 : -1];
48   int check1[count<int>::value == 1? 1 : -1];
49   int check2[count<float, double>::value == 2? 1 : -1];
50   int check3[count<char, signed char, unsigned char>::value == 3? 1 : -1];
51 }
52 
53 namespace Replace {
54   // Simple metafunction that replaces the template arguments of
55   // template template parameters with 'int'.
56   template<typename T>
57   struct EverythingToInt;
58 
59   template<template<typename ...> class TT, typename T1, typename T2>
60   struct EverythingToInt<TT<T1, T2> > {
61     typedef TT<int, int> type;
62   };
63 
64   int check0[is_same<EverythingToInt<tuple<double, float>>::type,
65              tuple<int, int>>::value? 1 : -1];
66 }
67 
68 namespace Math {
69   template<int ...Values>
70   struct double_values {
71     typedef int_tuple<Values*2 ...> type;
72   };
73 
74   int check0[is_same<double_values<1, 2, -3>::type,
75                      int_tuple<2, 4, -6>>::value? 1 : -1];
76 
77   template<int ...Values>
78   struct square {
79     typedef int_tuple<(Values*Values)...> type;
80   };
81 
82   int check1[is_same<square<1, 2, -3>::type,
83                      int_tuple<1, 4, 9>>::value? 1 : -1];
84 
85   template<typename IntTuple> struct square_tuple;
86 
87   template<int ...Values>
88   struct square_tuple<int_tuple<Values...>> {
89     typedef int_tuple<(Values*Values)...> type;
90   };
91 
92   int check2[is_same<square_tuple<int_tuple<1, 2, -3> >::type,
93                      int_tuple<1, 4, 9>>::value? 1 : -1];
94 
95   template<int ...Values> struct sum;
96 
97   template<int First, int ...Rest>
98   struct sum<First, Rest...> {
99     static const int value = First + sum<Rest...>::value;
100   };
101 
102   template<>
103   struct sum<> {
104     static const int value = 0;
105   };
106 
107   int check3[sum<1, 2, 3, 4, 5>::value == 15? 1 : -1];
108 
109 #if 0
110   // FIXME: Instantiation of this fails.
111   template<int ... Values>
112   struct lazy_sum {
113     int operator()() {
114       return sum<Values...>::value;
115     }
116   };
117 
118   void f() {
119     lazy_sum<1, 2, 3, 4, 5>()();
120   }
121 #endif
122 }
123 
124 namespace Indices {
125   template<unsigned I, unsigned N, typename IntTuple>
126   struct build_indices_impl;
127 
128   template<unsigned I, unsigned N, int ...Indices>
129   struct build_indices_impl<I, N, int_tuple<Indices...> >
130     : build_indices_impl<I+1, N, int_tuple<Indices..., I> > {
131   };
132 
133   template<unsigned N, int ...Indices>
134   struct build_indices_impl<N, N, int_tuple<Indices...> > {
135     typedef int_tuple<Indices...> type;
136   };
137 
138   template<unsigned N>
139   struct build_indices : build_indices_impl<0, N, int_tuple<> > { };
140 
141   int check0[is_same<build_indices<5>::type,
142                      int_tuple<0, 1, 2, 3, 4>>::value? 1 : -1];
143 }
144