class T {
public:
T();
};
class C : T {
public:
C(int);
};
T a = 1; // ill-formed: T(C(1)) not tried
— end example
struct A {
A();
A(A &&); // #1
template<typename T> A(T &&); // #2
};
struct B : A {
using A::A;
B(const B &); // #3
B(B &&) = default; // #4, implicitly deleted
struct X { X(X &&) = delete; } x;
};
extern B b1;
B b2 = static_cast<B&&>(b1); // calls #3: #1, #2, and #4 are not viable
struct C { operator B&&(); };
B b3 = C(); // calls #3
— end examplepostfix-expression ( expression-list )
postfix-expression: postfix-expression . id-expression postfix-expression -> id-expression primary-expression
operator conversion-type-id ( ) cv-qualifier ref-qualifier noexcept-specifier attribute-specifier-seq ;where cv-qualifier is the same cv-qualification as, or a greater cv-qualification than, cv, and where conversion-type-id denotes the type “pointer to function of (P) returning R”, or the type “reference to pointer to function of (P) returning R”, or the type “reference to function of (P) returning R”, a surrogate call function with the unique name call-function and having the form
R call-function ( conversion-type-id F, P a, …, P a) { return F (a, …, a); }is also considered as a candidate function.
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"; // ill-formed 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 exampleSubclause | Expression | As member function | As non-member function |
@a | (a).operator@ ( ) | operator@(a) | |
a@b | (a).operator@ (b) | operator@(a, b) | |
a=b | (a).operator= (b) | ||
a[b] | (a).operator[](b) | ||
a-> | (a).operator->( ) | ||
a@ | (a).operator@ (0) | operator@(a, 0) |
struct A {
operator int();
};
A operator+(const A&, const A&);
void m() {
A a, b;
a + b; // operator+(a, b) chosen over int(a) + int(b)
} — end example
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 <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*>
— end example
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 {
auto operator<=>(const S&, const S&) = default; // #1
bool operator<(const S&, const S&); // #2
};
bool b = S() < S(); // calls #2
— end example
struct S {
std::weak_ordering operator<=>(const S&, int); // #1
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
struct Y { Y(int); };
struct A { operator int(); };
Y y1 = A(); // error: A::operator int() is not a candidate
struct X { X(); };
struct B { operator X(); };
B b;
X x{{b}}; // error: B::operator X() is not a candidate
— 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); // 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
— end exampleConversion | 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 examplevoid 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
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(const volatile int *);
int f(const int *);
int i;
int j = f(&i); // calls f(const int*)
— end exampleint 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