struct A { A(); operator int(); operator double(); } a; int i = a; // a.operator int() followed by no conversion is better than // a.operator double() followed by a conversion to int float x = a; // ambiguous: both possibilities require conversions, // and neither is better than the other— end example
template <class T> struct A { operator T&(); // #1 operator T&&(); // #2 }; typedef int Fn(); A<Fn> a; Fn& lf = a; // calls #1 Fn&& rf = a; // calls #2— end example
struct A { A(int = 0); }; struct B: A { using A::A; B(); }; int main() { B b; // OK, B::B() }— end example
struct S { friend auto operator<=>(const S&, const S&) = default; // #1 friend bool operator<(const S&, const S&); // #2 }; bool b = S() < S(); // calls #2— end example
struct S { friend std::weak_ordering operator<=>(const S&, int); // #1 friend std::weak_ordering operator<=>(int, const S&); // #2 }; bool b = 1 < S(); // calls #2— end example
template <class T> struct A { using value_type = T; A(value_type); // #1 A(const A&); // #2 A(T, T, int); // #3 template<class U> A(int, T, U); // #4 // #5 is the copy deduction candidate, A(A) }; A x(1, 2, 3); // uses #3, generated from a non-template constructor template <class T> A(T) -> A<T>; // #6, less specialized than #5 A a(42); // uses #6 to deduce A<int> and #1 to initialize A b = a; // uses #5 to deduce A<int> and #2 to initialize template <class T> A(A<T>) -> A<A<T>>; // #7, as specialized as #5 A b2 = a; // uses #7 to deduce A<A<int>> and #1 to initialize— end example
void Fcn(const int*, short); void Fcn(int*, int); int i; short s = 0; void f() { Fcn(&i, s); // is ambiguous because &i → int* is better than &i → const int* // but s → short is also better than s → int Fcn(&i, 1L); // calls Fcn(int*, int), because &i → int* is better than &i → const int* // and 1L → short and 1L → int are indistinguishable Fcn(&i, 'c'); // calls Fcn(int*, int), because &i → int* is better than &i → const int* // and c → int is better than c → short }— end example
namespace A { extern "C" void f(int = 5); } namespace B { extern "C" void f(int = 5); } using A::f; using B::f; void use() { f(3); // OK, default argument was not used for viability f(); // error: found default argument twice }— end example
class B; class A { A (B&);}; class B { operator A (); }; class C { C (B&); }; void f(A) { } void f(C) { } B b; f(b); // error: ambiguous because there is a conversion b → C (via constructor) // and an (ambiguous) conversion b → A (via constructor or conversion function) void f(B) { } f(b); // OK, unambiguous— end example
Conversion | Category | Rank | Subclause |
No conversions required | Identity | ||
Lvalue-to-rvalue conversion | |||
Array-to-pointer conversion | Lvalue Transformation | ||
Function-to-pointer conversion | Exact Match | ||
Qualification conversions | |||
Function pointer conversion | Qualification Adjustment | ||
Integral promotions | |||
Floating-point promotion | Promotion | Promotion | |
Integral conversions | |||
Floating-point conversions | |||
Floating-integral conversions | |||
Pointer conversions | Conversion | Conversion | |
Pointer-to-member conversions | |||
Boolean conversions |
struct A {}; struct B : public A {} b; int f(A&); int f(B&); int i = f(b); // calls f(B&), an exact match, rather than f(A&), a conversion— end example
struct A { int x, y; }; struct B { int y, x; }; void f(A a, int); // #1 void f(B b, ...); // #2 void g(A a); // #3 void g(B b); // #4 void h() { f({.x = 1, .y = 2}, 0); // OK; calls #1 f({.y = 2, .x = 1}, 0); // error: selects #1, initialization of a fails // due to non-matching member order ([dcl.init.list]) g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4 }— end example
void f(std::initializer_list<int>); f( {} ); // OK: f(initializer_list<int>) identity conversion f( {1,2,3} ); // OK: f(initializer_list<int>) identity conversion f( {'a','b'} ); // OK: f(initializer_list<int>) integral promotion f( {1.0} ); // error: narrowing struct A { A(std::initializer_list<double>); // #1 A(std::initializer_list<complex<double>>); // #2 A(std::initializer_list<std::string>); // #3 }; A a{ 1.0,2.0 }; // OK, uses #1 void g(A); g({ "foo", "bar" }); // OK, uses #3 typedef int IA[3]; void h(const IA&); h({ 1, 2, 3 }); // OK: identity conversion— end example
struct A { A(std::initializer_list<int>); }; void f(A); f( {'a', 'b'} ); // OK: f(A(std::initializer_list<int>)) user-defined conversion struct B { B(int, double); }; void g(B); g( {'a', 'b'} ); // OK: g(B(int, double)) user-defined conversion g( {1.0, 1.0} ); // error: narrowing void f(B); f( {'a', 'b'} ); // error: ambiguous f(A) or f(B) struct C { C(std::string); }; void h(C); h({"foo"}); // OK: h(C(std::string("foo"))) struct D { D(A, C); }; void i(D); i({ {1,2}, {"bar"} }); // OK: i(D(A(std::initializer_list<int>{1,2}), C(std::string("bar"))))— end example
struct A { int m1; double m2; }; void f(A); f( {'a', 'b'} ); // OK: f(A(int,double)) user-defined conversion f( {1.0} ); // error: narrowing— end example
struct A { int m1; double m2; }; void f(const A&); f( {'a', 'b'} ); // OK: f(A(int,double)) user-defined conversion f( {1.0} ); // error: narrowing void g(const double &); g({1}); // same conversion as int to double— end example
void f(int); f( {'a'} ); // OK: same conversion as char to int f( {1.0} ); // error: narrowing— end example
void f(int); f( { } ); // OK: identity conversion— end example
void f1(int); // #1 void f1(std::initializer_list<long>); // #2 void g1() { f1({42}); } // chooses #2 void f2(std::pair<const char*, const char*>); // #3 void f2(std::initializer_list<std::string>); // #4 void g2() { f2({"foo","bar"}); } // chooses #4— end example
void f(int (&&)[] ); // #1 void f(double (&&)[] ); // #2 void f(int (&&)[2]); // #3 f( {1} ); // Calls #1: Better than #2 due to conversion, better than #3 due to bounds f( {1.0} ); // Calls #2: Identity conversion is better than floating-integral conversion f( {1.0, 2.0} ); // Calls #2: Identity conversion is better than floating-integral conversion f( {1, 2} ); // Calls #3: Converting to array of known bound is better than to unknown bound, // and an identity conversion is better than floating-integral conversion— end example
int i; int f1(); int&& f2(); int g(const int&); int g(const int&&); int j = g(i); // calls g(const int&) int k = g(f1()); // calls g(const int&&) int l = g(f2()); // calls g(const int&&) struct A { A& operator<<(int); void p() &; void p() &&; }; A& operator<<(A&&, char); A() << 1; // calls A::operator<<(int) A() << 'c'; // calls operator<<(A&&, char) A a; a << 1; // calls A::operator<<(int) a << 'c'; // calls A::operator<<(int) A().p(); // calls A::p()&& a.p(); // calls A::p()&— end example
int f(void(&)()); // #1 int f(void(&&)()); // #2 void g(); int i1 = f(g); // calls #1— end example
int f(const volatile int *); int f(const int *); int i; int j = f(&i); // calls f(const int*)— end example
int f(const int &); int f(int &); int g(const int &); int g(int); int i; int j = f(i); // calls f(int &) int k = g(i); // ambiguous struct X { void f() const; void f(); }; void g(const X& a, X b) { a.f(); // calls X::f() const b.f(); // calls X::f() }— end example
struct A { operator short(); } a; int f(int); int f(float); int i = f(a); // calls f(int), because short → int is // better than short → float.— end example
struct A {}; struct B : public A {}; struct C : public B {}; C* pc; int f(A*); int f(B*); int i = f(pc); // calls f(B*)— end example