class T { public: T(); }; class C : T { public: C(int); }; T a = 1; // error: no viable conversion (T(C(1)) not considered)— end example
struct A { A(); // #1 A(A &&); // #2 template<typename T> A(T &&); // #3 }; struct B : A { using A::A; B(const B &); // #4 B(B &&) = default; // #5, implicitly deleted struct X { X(X &&) = delete; } x; }; extern B b1; B b2 = static_cast<B&&>(b1); // calls #4: #1 is not viable, #2, #3, and #5 are not candidates struct C { operator B&&(); }; B b3 = C(); // calls #4— end example
int f1(int); int f2(float); typedef int (*fp1)(int); typedef int (*fp2)(float); struct A { operator fp1() { return f1; } operator fp2() { return f2; } } a; int i = a(1); // calls f1 via pointer returned from conversion function— end example
struct String { String (const String&); String (const char*); operator const char* (); }; String operator + (const String&, const String&); void f() { const char* p= "one" + "two"; // error: cannot add two pointers; overloaded operator+ not considered // because neither operand has class or enumeration type int I = 1 + 1; // always evaluates to 2 even if class or enumeration types exist // that would perform the operation. }— end example
Subclause | Expression | As member function | As non-member function |
@a | |||
a@b | |||
a=b | |||
a[b] | |||
a-> | |||
a@ |
struct X { operator double(); }; struct Y { operator int*(); }; int *a = Y() + 100.0; // error: pointer arithmetic requires integral operand int *b = Y() + X(); // error: pointer arithmetic requires integral operand— end example
struct A { }; void operator + (A, A); struct B { void operator + (B); void f (); }; A a; void B::f() { operator+ (a,a); // error: global operator hidden by member a + a; // OK: calls global operator+ }— end note
template <typename> class AA;with a single partial specialization whose template parameter list is that of A and whose template argument list is a specialization of A with the template argument list of A ([temp.dep.type]), AA<T> matches the partial specialization.
template <class T> struct A { explicit A(const T&, ...) noexcept; // #1 A(T&&, ...); // #2 }; int i; A a1 = { i, i }; // error: explicit constructor #1 selected in copy-list-initialization during deduction, // cannot deduce from non-forwarding rvalue reference in #2 A a2{i, i}; // OK, #1 deduces to A<int> and also initializes A a3{0, i}; // OK, #2 deduces to A<int> and also initializes A a4 = {0, i}; // OK, #2 deduces to A<int> and also initializes template <class T> A(const T&, const T&) -> A<T&>; // #3 template <class T> explicit A(T&&, T&&) -> A<T>; // #4 A a5 = {0, 1}; // error: explicit deduction guide #4 selected in copy-list-initialization during deduction A a6{0,1}; // OK, #4 deduces to A<int> and #2 initializes A a7 = {0, i}; // error: #3 deduces to A<int&>, #1 and #2 declare same constructor A a8{0,i}; // error: #3 deduces to A<int&>, #1 and #2 declare same constructor template <class T> struct B { template <class U> using TA = T; template <class U> B(U, TA<U>); }; B b{(int*)0, (char*)0}; // OK, deduces B<char*> template <typename T> struct S { T x; T y; }; template <typename T> struct C { S<T> s; T t; }; template <typename T> struct D { S<int> s; T t; }; C c1 = {1, 2}; // error: deduction failed C c2 = {1, 2, 3}; // error: deduction failed C c3 = {{1u, 2u}, 3}; // OK, deduces C<int> D d1 = {1, 2}; // error: deduction failed D d2 = {1, 2, 3}; // OK, braces elided, deduces D<int> template <typename T> struct E { T t; decltype(t) t2; }; E e1 = {1, 2}; // OK, deduces E<int> template <typename... T> struct Types {}; template <typename... T> struct F : Types<T...>, T... {}; struct X {}; struct Y {}; struct Z {}; struct W { operator Y(); }; F f1 = {Types<X, Y, Z>{}, {}, {}}; // OK, F<X, Y, Z> deduced F f2 = {Types<X, Y, Z>{}, X{}, Y{}}; // OK, F<X, Y, Z> deduced F f3 = {Types<X, Y, Z>{}, X{}, W{}}; // error: conflicting types deduced; operator Y not considered— end example
template <class T, class U> struct C { C(T, U); // #1 }; template<class T, class U> C(T, U) -> C<T, std::type_identity_t<U>>; // #2 template<class V> using A = C<V *, V *>; template<std::integral W> using B = A<W>; int i{}; double d{}; A a1(&i, &i); // deduces A<int> A a2(i, i); // error: cannot deduce V * from i A a3(&i, &d); // error: #1: cannot deduce (V*, V*) from (int *, double *) // #2: cannot deduce A<V> from C<int *, double *> B b1(&i, &i); // deduces B<int> B b2(&d, &d); // error: cannot deduce B<W> from C<double *, double *>
// The following concept ensures a specialization of A is deduced. template <class> class AA; template <class V> class AA<A<V>> { }; template <class T> concept deduces_A = requires { sizeof(AA<T>); }; // f1 is formed from the constructor #1 of C, generating the following function template template<T, U> auto f1(T, U) -> C<T, U>; // Deducing arguments for C<T, U> from C<V *, V*> deduces T as V * and U as V *; // f1' is obtained by transforming f1 as described by the above procedure. template<class V> requires deduces_A<C<V *, V *>> auto f1_prime(V *, V*) -> C<V *, V *>; // f2 is formed from the deduction-guide #2 of C template<class T, class U> auto f2(T, U) -> C<T, std::type_identity_t<U>>; // Deducing arguments for C<T, std::type_identity_t<U>> from C<V *, V*> deduces T as V *; // f2' is obtained by transforming f2 as described by the above procedure. template<class V, class U> requires deduces_A<C<V *, std::type_identity_t<U>>> auto f2_prime(V *, U) -> C<V *, std::type_identity_t<U>>; // The following concept ensures a specialization of B is deduced. template <class> class BB; template <class V> class BB<B<V>> { }; template <class T> concept deduces_B = requires { sizeof(BB<T>); }; // The guides for B derived from the above f1' and f2' for A are as follows: template<std::integral W> requires deduces_A<C<W *, W *>> && deduces_B<C<W *, W *>> auto f1_prime_for_B(W *, W *) -> C<W *, W *>; template<std::integral W, class U> requires deduces_A<C<W *, std::type_identity_t<U>>> && deduces_B<C<W *, std::type_identity_t<U>>> auto f2_prime_for_B(W *, U) -> C<W *, std::type_identity_t<U>>;