| // RUN: %clang_cc1 -std=c++1z -verify %s |
| |
| // Test that we cope with failure to expand a pack. |
| template<typename ...T> struct Unexpanded : T... { |
| using T::f; // expected-error {{unexpanded}} |
| using typename T::type; // expected-error {{unexpanded}} |
| template<typename ...U> void g(U ...u) { f(u...); } // expected-error {{undeclared identifier 'f'}} |
| void h() { |
| Unexpanded<type...> *p; // expected-error {{undeclared identifier 'type'}} |
| } |
| }; |
| void test_Unexpanded() { |
| struct A { void f(); }; // expected-note {{must qualify}} |
| struct B { void f(int); }; // expected-note {{must qualify}} |
| Unexpanded<A, B>().g(0); // expected-note {{instantiation of}} |
| } |
| |
| // Test using non-type members from pack of base classes. |
| template<typename ...T> struct A : T... { // expected-note 2{{candidate}} |
| using T::T ...; // expected-note 2{{inherited here}} |
| using T::operator() ...; |
| using T::operator T* ...; |
| using T::h ...; |
| |
| void f(int n) { h(n); } // expected-error {{ambiguous}} |
| void f(int n, int m) { h(n, m); } // expected-error {{member using declaration 'h' instantiates to an empty pack}} |
| void g(int n) { (*this)(n); } // expected-error {{ambiguous}} |
| void g(int n, int m) { (*this)(n, m); } // expected-error {{does not provide a call operator}} |
| }; |
| |
| namespace test_A { |
| struct X { |
| X(); |
| X(int); // expected-note {{candidate}} |
| void operator()(int); // expected-note 2{{candidate}} |
| operator X *(); |
| void h(int); // expected-note {{candidate}} |
| }; |
| struct Y { |
| Y(); |
| Y(int, int); |
| void operator()(int, int); |
| operator Y *(); |
| void h(int, int); // expected-note {{not viable}} |
| }; |
| struct Z { |
| Z(); |
| Z(int); // expected-note {{candidate}} |
| void operator()(int); // expected-note 2{{candidate}} |
| operator Z *(); |
| void h(int); // expected-note {{candidate}} |
| }; |
| |
| void f() { |
| A<> a; |
| a.f(0, 0); // expected-note {{instantiation of}} |
| a.g(0, 0); // expected-note {{instantiation of}} |
| |
| A<X, Y> axy(0); |
| A<X, Y>(0, 0); |
| axy.f(0); |
| axy.f(0, 0); |
| axy.g(0); |
| axy.g(0, 0); |
| axy(0); |
| axy(0, 0); |
| |
| A<X, Y, Z>(0); // expected-error {{ambiguous}} |
| A<X, Y, Z> axyz(0, 0); |
| axyz.f(0); // expected-note {{instantiation of}} |
| axyz.f(0, 0); |
| axyz.g(0); // expected-note {{instantiation of}} |
| axyz.g(0, 0); |
| axyz(0); // expected-error {{ambiguous}} |
| axyz(0, 0); |
| |
| X *x; |
| x = a; // expected-error {{incompatible}} |
| x = axy; |
| x = axyz; |
| x = a.operator X*(); // expected-error {{no member}} |
| x = axy.operator X*(); |
| x = axyz.operator X*(); |
| |
| Z *z; |
| z = axyz; |
| z = axyz.operator Z*(); |
| } |
| } |
| |
| // Test using pack of non-type members from single base class. |
| template<typename X, typename Y, typename ...T> struct B : X, Y { |
| using X::operator T* ...; |
| }; |
| |
| namespace test_B { |
| struct X { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} |
| struct Y { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} |
| B<X, Y, int, float> bif; |
| int *pi = bif; |
| float *pf = bif; |
| char *pc = bif; // expected-error {{ambiguous}} |
| } |
| |
| // Test using type member from pack of base classes. |
| template<typename ...T> struct C : T... { |
| using typename T::type ...; // expected-error {{target of using declaration conflicts}} |
| void f() { type value; } // expected-error {{member using declaration 'type' instantiates to an empty pack}} |
| }; |
| |
| namespace test_C { |
| struct X { typedef int type; }; |
| struct Y { typedef int type; }; // expected-note {{conflicting}} |
| struct Z { typedef float type; }; // expected-note {{target}} |
| |
| void f() { |
| C<> c; |
| c.f(); // expected-note {{instantiation of}} |
| |
| C<X, Y> cxy; |
| cxy.f(); |
| |
| C<X, Y, Z> cxyz; // expected-note {{instantiation of}} |
| cxyz.f(); |
| } |
| } |
| |
| // Test using pack of non-types at block scope. |
| template<typename ...T> int fn1() { |
| using T::e ...; // expected-error 2{{class member}} expected-note 2{{instead}} |
| // expected-error@-1 2{{produces multiple values}} |
| return e; // expected-error {{using declaration 'e' instantiates to an empty pack}} |
| } |
| |
| namespace test_fn1 { |
| struct X { static int e; }; |
| struct Y { typedef int e; }; |
| inline namespace P { enum E { e }; } |
| inline namespace Q { enum F { e }; } |
| void f() { |
| fn1<>(); // expected-note {{instantiation of}} |
| fn1<X>(); // expected-note {{instantiation of}} |
| fn1<Y>(); // expected-note {{instantiation of}} |
| fn1<E>(); |
| fn1<E, F>(); // expected-note {{instantiation of}} |
| fn1<E, X>(); // expected-note {{instantiation of}} |
| } |
| } |
| |
| // Test using pack of types at block scope. |
| template<typename ...T> void fn2() { |
| // This cannot ever be valid: in order for T::type to be a type, T must be a |
| // class, and a class member cannot be named by a block-scope using declaration. |
| using typename T::type ...; // expected-error {{class member}} |
| type x; // expected-error {{unknown type name 'type'}} |
| } |
| |
| // Test partial substitution into class-scope pack. |
| template<typename ...T> auto lambda1() { |
| return [](auto x) { |
| struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}} |
| using T::template X<decltype(x)>::f ...; |
| using typename T::template X<decltype(x)>::type ...; |
| void g(int n) { f(n); } // expected-error {{empty pack}} expected-error {{expected 2, have 1}} expected-error {{ambiguous}} |
| void h() { type value; } // expected-error {{empty pack}} |
| }; |
| return A(); |
| }; |
| } |
| |
| namespace test_lambda1 { |
| struct A { |
| template<typename> struct X { |
| void f(int); // expected-note {{candidate}} |
| using type = int; |
| }; |
| }; |
| struct B { |
| template<typename> struct X { |
| void f(int, int); // expected-note {{declared here}} expected-note {{not viable}} |
| using type = int; |
| }; |
| }; |
| struct C { |
| template<typename> struct X { |
| void f(int); // expected-note {{candidate}} |
| void f(int, int); // expected-note {{not viable}} |
| using type = int; |
| }; |
| }; |
| |
| void f() { |
| lambda1<>() // expected-note 2{{instantiation of}} |
| (0) |
| // FIXME: This is poor error recovery |
| .g(0); // expected-error {{no member named 'g'}} |
| lambda1<A>() |
| (0) |
| .g(0); |
| lambda1<B>() |
| (0) // expected-note {{instantiation of}} |
| .g(0); |
| lambda1<A, B, C>() |
| (0) // expected-note {{instantiation of}} |
| .g(0); |
| } |
| } |
| |
| namespace p0195r2_example { |
| template<typename ...Ts> |
| struct Overloader : Ts... { |
| using Ts::operator() ...; |
| }; |
| |
| template<typename ...Ts> |
| constexpr auto make_overloader(Ts &&...ts) { |
| return Overloader<Ts...>{static_cast<Ts&&>(ts)...}; |
| } |
| |
| void test() { |
| auto o = make_overloader( |
| [&](int &r) -> int & { return r; }, // expected-note {{candidate function}} |
| [&](float &r) -> float & { return r; } // expected-note {{candidate function}} |
| ); |
| int a; float f; double d; |
| int &ra = o(a); |
| float &rf = o(f); |
| double &rd = o(d); // expected-error {{no matching function}} |
| } |
| } |