// { dg-do compile { target c++17 } } // { dg-options "-fconcepts" } // { dg-skip-if "requires hosted libstdc++ for cassert" { ! hostedlib } } #include #include template concept C = __is_class(T); template concept Type = true; struct S { }; int called; // Basic terse notation void f(auto x) { called = 1; } void g(C auto x) { called = 2; } // Overloading generic functions void h(auto x) { called = 1; } void h(C auto x) { called = 2; } void p(auto x); void p(C auto x); struct S1 { void f1(auto x) { called = 1; } void f2(C auto x) { called = 2; } void f3(auto x) { called = 1; } void f3(C auto x) { called = 2; } }; template struct S2 { void f1(auto x) { called = 1; } void f2(C auto x) { called = 2; } void f3(auto x) { called = 1; } void f3(C auto x) { called = 2; } void h1(auto x); void h2(C auto x); void h3(auto x); void h3(C auto x); template void g1(T t, U u) { called = 1; } template void g2(T t, U u); }; void ptr(C auto *) { called = 1; } void ptr(const C auto*) { called = 2; } void ref(C auto &) { called = 1; } void ref(const C auto&) { called = 2; } void fwd_lvalue_ref(Type auto&& x) { using T = decltype(x); static_assert(std::is_lvalue_reference::value, "not an lvlaue reference"); } void fwd_const_lvalue_ref(Type auto&& x) { using T = decltype(x); static_assert(std::is_lvalue_reference::value, "not an lvalue reference"); using U = typename std::remove_reference::type; static_assert(std::is_const::value, "not const-qualified"); } void fwd_rvalue_ref(Type auto&& x) { using T = decltype(x); static_assert(std::is_rvalue_reference::value, "not an rvalue reference"); } // Make sure we can use nested names speicifers for concept names. namespace N { template concept C = true; } // namespace N void foo(N::C auto x) { } int main() { S s; const S cs; f(0); assert(called == 1); g(s); assert(called == 2); h(0); assert(called == 1); h(s); assert(called == 2); S1 s1; s1.f1(0); assert(called == 1); s1.f2(s); assert(called == 2); s1.f3(0); assert(called == 1); s1.f3(s); assert(called == 2); S2 s2; s2.f1(0); assert(called == 1); s2.f2(s); assert(called == 2); s2.f3(0); assert(called == 1); s2.f3(s); assert(called == 2); s2.h1(0); assert(called == 1); s2.h2(s); assert(called == 2); s2.h3(0); assert(called == 1); s2.h3(s); assert(called == 2); s2.g1(s, s); assert(called == 1); s2.g2(s, s); assert(called == 2); ptr(&s); assert(called == 1); ptr(&cs); assert(called == 2); ref(s); assert(called == 1); ref(cs); assert(called == 2); // Check forwarding problems fwd_lvalue_ref(s); fwd_const_lvalue_ref(cs); fwd_rvalue_ref(S()); foo(0); } // Test that decl/def matching works. void p(auto x) { called = 1; } void p(C auto x) { called = 2; } template void S2::h1(auto x) { called = 1; } template void S2::h2(C auto x) { called = 2; } template void S2::h3(auto x) { called = 1; } template void S2::h3(C auto x) { called = 2; } template template void S2::g2(T t, U u) { called = 2; }