summaryrefslogtreecommitdiffstats
path: root/test/SemaTemplate/deduction.cpp
blob: e9422898c07d46c2a6429621ca1902133bb1d11b (plain)
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11

// Template argument deduction with template template parameters.
template<typename T, template<T> class A> 
struct X0 {
  static const unsigned value = 0;
};

template<template<int> class A>
struct X0<int, A> {
  static const unsigned value = 1;
};

template<int> struct X0i;
template<long> struct X0l;
int array_x0a[X0<long, X0l>::value == 0? 1 : -1];
int array_x0b[X0<int, X0i>::value == 1? 1 : -1];

template<typename T, typename U>
struct is_same {
  static const bool value = false;
};

template<typename T>
struct is_same<T, T> {
  static const bool value = true;
};

template<typename T> struct allocator { };
template<typename T, typename Alloc = allocator<T> > struct vector {};

// Fun with meta-lambdas!
struct _1 {};
struct _2 {};

// Replaces all occurrences of _1 with Arg1 and _2 with Arg2 in T.
template<typename T, typename Arg1, typename Arg2>
struct Replace {
  typedef T type;
};

// Replacement of the whole type.
template<typename Arg1, typename Arg2>
struct Replace<_1, Arg1, Arg2> {
  typedef Arg1 type;
};

template<typename Arg1, typename Arg2>
struct Replace<_2, Arg1, Arg2> {
  typedef Arg2 type;
};

// Replacement through cv-qualifiers
template<typename T, typename Arg1, typename Arg2>
struct Replace<const T, Arg1, Arg2> {
  typedef typename Replace<T, Arg1, Arg2>::type const type;
};

// Replacement of templates
template<template<typename> class TT, typename T1, typename Arg1, typename Arg2>
struct Replace<TT<T1>, Arg1, Arg2> {
  typedef TT<typename Replace<T1, Arg1, Arg2>::type> type;
};

template<template<typename, typename> class TT, typename T1, typename T2,
         typename Arg1, typename Arg2>
struct Replace<TT<T1, T2>, Arg1, Arg2> {
  typedef TT<typename Replace<T1, Arg1, Arg2>::type,
             typename Replace<T2, Arg1, Arg2>::type> type;
};

// Just for kicks...
template<template<typename, typename> class TT, typename T1,
         typename Arg1, typename Arg2>
struct Replace<TT<T1, _2>, Arg1, Arg2> {
  typedef TT<typename Replace<T1, Arg1, Arg2>::type, Arg2> type;
};

int array0[is_same<Replace<_1, int, float>::type, int>::value? 1 : -1];
int array1[is_same<Replace<const _1, int, float>::type, const int>::value? 1 : -1];
int array2[is_same<Replace<vector<_1>, int, float>::type, vector<int> >::value? 1 : -1];
int array3[is_same<Replace<vector<const _1>, int, float>::type, vector<const int> >::value? 1 : -1];
int array4[is_same<Replace<vector<int, _2>, double, float>::type, vector<int, float> >::value? 1 : -1];

// PR5911
template <typename T, int N> void f(const T (&a)[N]);
int iarr[] = { 1 };
void test_PR5911() { f(iarr); }

// Must not examine base classes of incomplete type during template argument
// deduction.
namespace PR6257 {
  template <typename T> struct X {
    template <typename U> X(const X<U>& u);
  };
  struct A;
  void f(A& a);
  void f(const X<A>& a);
  void test(A& a) { (void)f(a); }
}

// PR7463
namespace PR7463 {
  const int f ();
  template <typename T_> void g (T_&); // expected-note{{T_ = int}}
  void h (void) { g(f()); } // expected-error{{no matching function for call}}
}

namespace test0 {
  template <class T> void make(const T *(*fn)()); // expected-note {{candidate template ignored: can't deduce a type for 'T' which would make 'const T' equal 'char'}}
  char *char_maker();
  void test() {
    make(char_maker); // expected-error {{no matching function for call to 'make'}}
  }
}

namespace test1 {
  template<typename T> void foo(const T a[3][3]);
  void test() {
    int a[3][3];
    foo(a);
  }
}

// PR7708
namespace test2 {
  template<typename T> struct Const { typedef void const type; };

  template<typename T> void f(T, typename Const<T>::type*);
  template<typename T> void f(T, void const *);

  void test() {
    void *p = 0;
    f(0, p);
  }
}

// rdar://problem/8537391
namespace test3 {
  struct Foo {
    template <void F(char)> static inline void foo();
  };

  class Bar {
    template<typename T> static inline void wobble(T ch);

  public:
    static void madness() {
      Foo::foo<wobble<char> >();
    }
  };
}

// Verify that we can deduce enum-typed arguments correctly.
namespace test14 {
  enum E { E0, E1 };
  template <E> struct A {};
  template <E e> void foo(const A<e> &a) {}

  void test() {
    A<E0> a;
    foo(a);
  }
}

namespace PR21536 {
  template<typename ...T> struct X;
  template<typename A, typename ...B> struct S {
    static_assert(sizeof...(B) == 1, "");
    void f() {
      using T = A;
      using T = int;

      using U = X<B...>;
      using U = X<int>;
    }
  };
  template<typename ...T> void f(S<T...>);
  void g() { f(S<int, int>()); }
}

namespace PR19372 {
  template <template<typename...> class C, typename ...Us> struct BindBack {
    template <typename ...Ts> using apply = C<Ts..., Us...>;
  };
  template <typename, typename...> struct Y;
  template <typename ...Ts> using Z = Y<Ts...>;

  using T = BindBack<Z, int>::apply<>;
  using T = Z<int>;

  using U = BindBack<Z, int, int>::apply<char>;
  using U = Z<char, int, int>;
}