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
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
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
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
}
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
}
struct Y { Y(int); };
struct A { operator int(); };
Y y1 = A(); // error: A::operator int() is not a candidate
struct X { };
struct B { operator X(); };
B b;
X x({b}); // error: B::operator X() is not a candidate
class B;
class A { A (B&);};
class B { operator A (); };
class C { C (B&); };
void f(A) { }
void f(C) { }
B b;
f(b); // ill-formed: 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
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
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
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"))))
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
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
void f(int);
f( {'a'} ); // OK: same conversion as char to int
f( {1.0} ); // error: narrowing
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
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()&
int f(void(&)()); // #1 int f(void(&&)()); // #2 void g(); int i1 = f(g); // calls #1
int f(const volatile int *);
int f(const int *);
int i;
int j = f(&i); // calls f(const int*)
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() }
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.
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*)