template <class myType>
myType GetMax (myType a, myType b) {
return (a>b?a:b);
}
int x,y;
GetMax <int> (x,y);
#include <iostream>
using namespace std;
template <class T>
T GetMax (T a, T b) {
T result;
result = (a>b)? a : b;
return (result);
}
int main () {
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax<int>(i,j);
n=GetMax<long>(l,m);
cout << k << endl;
cout << n << endl;
return 0;
}
Class templates
#include <iostream>
using namespace std;
template <class T>
class mypair {
T a, b;
public:
mypair (T first, T second)
{a=first; b=second;}
T getmax ();
};
template <class T>
T mypair<T>::getmax ()
{
T retval;
retval = a>b? a : b;
return retval;
}
int main () {
mypair <int> myobject (100, 75);
cout << myobject.getmax();
return 0;
}
#include <iostream>
using namespace std;
// class template:
template <class T>
class mycontainer {
T element;
public:
mycontainer (T arg) {element=arg;}
T increase () {return ++element;}
};
// class template specialization:
template <>
class mycontainer <char> {
char element;
public:
mycontainer (char arg) {element=arg;}
char uppercase ()
{
if ((element>='a')&&(element<='z'))
element+='A'-'a';
return element;
}
};
int main () {
mycontainer<int> myint (7);
mycontainer<char> mychar ('j');
cout << myint.increase() << endl;
cout << mychar.uppercase() << endl;
return 0;
}
#include <iostream>
using namespace std;
template <class T, int N>
class mysequence {
T memblock [N];
public:
void setmember (int x, T value);
T getmember (int x);
};
template <class T, int N>
void mysequence<T,N>::setmember (int x, T value) {
memblock[x]=value;
}
template <class T, int N>
T mysequence<T,N>::getmember (int x) {
return memblock[x];
}
int main () {
mysequence <int,5> myints;
mysequence <double,5> myfloats;
myints.setmember (0,100);
myfloats.setmember (3,3.1416);
cout << myints.getmember(0) << '\n';
cout << myfloats.getmember(3) << '\n';
return 0;
}
Parameter pack or Variadics template
template<class ... Types> void f(Types ... args);
f(); // OK: args contains no arguments
f(1); // OK: args contains one argument: int
f(2, 1.0); // OK: args contains two arguments: int and double
template<typename... Ts, typename U> struct Invalid; // Error: Ts.. not at the end
template<typename ...Ts, typename U, typename=void>
void valid(U, Ts...); // OK: can deduce U
// void valid(Ts..., U); // Can't be used: Ts... is a non-deduced context in this position
valid(1.0, 1, 2, 3); // OK: deduces U as double, Ts as {int,int,int}
Pack expansion
template<class ...Us> void f(Us... pargs) {}
template<class ...Ts> void g(Ts... args) {
f(&args...); // “&args...” is a pack expansion
// “&args” is its pattern
}
g(1, 0.2, "a"); // Ts... args expand to int E1, double E2, const char* E3
// &args... expands to &E1, &E2, &E3
// Us... pargs expand to int* E1, double* E2, const char** E3
// The base case: we just have a single number.
template <typename T>
double sum(T t) {
cout<<"call base sum\n";// call once at the last of recursion
return t;
}
// The recursive case: we take a number, alongside
// some other numbers, and produce their sum.
template <typename T, typename... Rest>
double sum(T t, Rest... rest) {
cout<<"call main sum\n";//call first 3 times
return t + sum(rest...);
}
int main(int argc,char* argv[]){
cout<<sum(1,2,3,4);//10
return 0;
}
Template Specialize style
template <class T,class ...TT>
class AA;
template <class T,class ...TT>
class AA<T(TT...)>{
};
struct Base { virtual int g(); virtual ~Base() {} };
struct A : Base {
// OK: declares three member virtual functions, two of them pure
virtual int f() = 0, g() override = 0, h();
// OK: destructor can be pure too
~A() = 0;
// Error: pure-specifier on a function definition
virtual int b()=0 {}
};
struct A
{
virtual void foo();
void bar();
};
struct B : A
{
void foo() const override; // Error: B::foo does not override A::foo
// (signature mismatch)
void foo() override; // OK: B::foo overrides A::foo
void bar() override; // Error: A::bar is not virtual
};
final specifier
struct Base
{
virtual void foo();
};
struct A : Base
{
void foo() final; // Base::foo is overridden and A::foo is the final override
void bar() final; // Error: bar cannot be final as it is non-virtual
};
struct B final : A // struct B is final
{
void foo() override; // Error: foo cannot be overridden as it is final in A
};
struct C : B // Error: B is final
{
};
friend declaration
class Y {
int data; // private member
// the non-member function operator<< will have access to Y's private members
friend std::ostream& operator<<(std::ostream& out, const Y& o);
friend char* X::foo(int); // members of other classes can be friends too
friend X::X(char), X::~X(); // constructors and destructors can be friends
};
// friend declaration does not declare a member function
// this operator<< still needs to be defined, as a non-member
std::ostream& operator<<(std::ostream& out, const Y& y)
{
return out << y.data; // can access private member Y::data
}
class F {};
int f();
int main()
{
extern int g();
class Local { // Local class in the main() function
friend int f(); // Error, no such function declared in main()
friend int g(); // OK, there is a declaration for g in main()
friend class F; // friends a local F (defined later)
friend class ::F; // friends the global F
};
class F {}; // local F
}
Bit field
#include <iostream>
struct S {
// will usually occupy 2 bytes:
// 3 bits: value of b1
// 2 bits: unused
// 6 bits: value of b2
// 2 bits: value of b3
// 3 bits: unused
unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
};
int main()
{
std::cout << sizeof(S) << '\n'; // usually prints 2
}
#include <iostream>
struct S {
// will usually occupy 2 bytes:
// 3 bits: value of b1
// 5 bits: unused
// 6 bits: value of b2
// 2 bits: value of b3
unsigned char b1 : 3;
unsigned char :0; // start a new byte
unsigned char b2 : 6;
unsigned char b3 : 2;
};
int main()
{
std::cout << sizeof(S) << '\n'; // usually prints 2
}
If the specified size of the bit field is greater than the size of its type, the value is limited by the type: a std::uint8_t b : 1000; would still hold values between 0 and 255. the extra bits become unused padding.
This Pointer
class T
{
int x;
void foo()
{
x = 6; // same as this->x = 6;
this->x = 5; // explicit use of this->
}
void foo() const
{
// x = 7; // Error: *this is constant
}
void foo(int x) // parameter x shadows the member with the same name
{
this->x = x; // unqualified x refers to the parameter
// 'this->' required for disambiguation
}
int y;
T(int x) : x(x), // uses parameter x to initialize member x
y(this->x) // uses member x to initialize member y
{}
T& operator= ( const T& b )
{
x = b.x;
return *this; // many overloaded operators return *this
}
};
class Outer {
int a[sizeof(*this)]; // error: not inside a member function
unsigned int sz = sizeof(*this); // OK: in default member initializer
void f() {
int b[sizeof(*this)]; // OK
struct Inner {
int c[sizeof(*this)]; // error: not inside a member function of Inner
};
}
}
Constructors and member initializer lists
#include <fstream>
#include <string>
#include <mutex>
struct Base {
int n;
};
struct Class : public Base
{
unsigned char x;
unsigned char y;
std::mutex m;
std::lock_guard<std::mutex> lg;
std::fstream f;
std::string s;
Class ( int x )
: Base { 123 }, // initialize base class
x ( x ), // x (member) is initialized with x (parameter)
y { 0 }, // y initialized to 0
f{"test.cc", std::ios::app}, // this takes place after m and lg are initialized
s(__func__), //__func__ is available because init-list is a part of constructor
lg ( m ), // lg uses m, which is already initialized
m{} // m is initialized before lg even though it appears last here
{} // empty compound statement
Class ( double a )
: y ( a+1 ),
x ( y ), // x will be initialized before y, its value here is indeterminate
lg ( m )
{} // base class initializer does not appear in the list, it is
// default-initialized (not the same as if Base() were used, which is value-init)
Class()
try // function-try block begins before the function body, which includes init list
: Class( 0.0 ) //delegate constructor
{
// ...
}
catch (...)
{
// exception occurred on initialization
}
};
int main() {
Class c;
Class c1(1);
Class c2(0.1);
}
Default constructors
struct A
{
int x;
A(int x = 1): x(x) {} // user-defined default constructor
};
struct B: A
{
// B::B() is implicitly-defined, calls A::A()
};
struct C
{
A a;
// C::C() is implicitly-defined, calls A::A()
};
struct D: A
{
D(int y): A(y) {}
// D::D() is not declared because another constructor exists
};
struct E: A
{
E(int y): A(y) {}
E() = default; // explicitly defaulted, calls A::A()
};
struct F
{
int& ref; // reference member
const int c; // const member
// F::F() is implicitly defined as deleted
};
int main()
{
A a;
B b;
C c;
// D d; // compile error
E e;
// F f; // compile error
}
Destructor
#include <iostream>
struct A
{
int i;
A ( int i ) : i ( i )
{
std::cout << "ctor a" << i << '\n';
}
~A()
{
std::cout << "dtor a" << i << '\n';
}
};
A a0(0);
int main()
{
A a1(1);
A* p;
{ // nested scope
A a2(2);
p = new A(3);
} // a2 out of scope
delete p; // calls the destructor of a3
}
Copy constructors
struct A
{
int n;
A(int n = 1) : n(n) { }
A(const A& a) : n(a.n) { } // user-defined copy ctor
};
struct B : A
{
// implicit default ctor B::B()
// implicit copy ctor B::B(const B&)
};
struct C : B
{
C() : B() { }
private:
C(const C&); // non-copyable, C++98 style
};
int main()
{
A a1(7);
A a2(a1); // calls the copy ctor
B b;
B b2 = b;
A a3 = b; // conversion to A& and copy ctor
volatile A va(10);
// A a4 = va; // compile error
C c;
// C c2 = c; // compile error
}
class S {
int d1; // non-static data member
int a[10] = {1,2}; // non-static data member with initializer (C++11)
static const int d2 = 1; // static data member with initializer
virtual void f1(int) = 0; // pure virtual member function
std::string d3, *d4, f2(int); // two data members and a member function
enum {NORTH, SOUTH, EAST, WEST};
struct NestedS {
std::string s;
} d5, *d6;
typedef NestedS value_type, *pointer_type;
}
Function definitions
class M {
std::size_t C;
std::vector<int> data;
public:
M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // constructor definition
int operator()(size_t r, size_t c) const { // member function definition
return data[r*C+c];
}
int& operator()(size_t r, size_t c) { // another member function definition
return data[r*C+c];
}
};
class S {
public:
S(); // public constructor
S(const S&); // public copy constructor
virtual ~S(); // public virtual destructor
private:
int* ptr; // private data member
};
class Base {
protected:
int d;
};
class Derived : public Base {
public:
using Base::d; // make Base's protected member d a public member of Derived
using Base::Base; // inherit all parent's constructors (C++11)
};
template <typename T>
struct identity
{
using type = T;
};
local struct
int main()
{
std::vector<int> v{1,2,3};
struct Local {
bool operator()(int n, int m) {
return n > m;
}
};
std::sort(v.begin(), v.end(), Local()); // since C++11
for(int n: v) std::cout << n << ' ';
}
injected-class-name
int X;
struct X {
void f() {
X* p; // OK. X refers to the injected-class-name
::X* q; // Error: name lookup finds a variable name, which hides the struct name
}
};
struct A {
A();
A(int);
template<class T> A(T) {}
};
using A_alias = A;
A::A() {}
A_alias::A(int) {}
template A::A(double);
struct B : A {
using A_alias::A;
};
A::A a; // Error: A::A is considered to name a constructor, not a type
struct A::A a2; // OK, same as 'A a2;'
B::A b; // OK, same as 'A b;'
Non-static data members
struct A { int a; char b; };
struct B { const int b1; volatile char b2; };
// A and B's common initial sequence is A.a, A.b and B.b1, B.b2
struct C { int c; unsigned : 0; char b; };
// A and C's common initial sequence is A.a and C.c
struct D { int d; char b : 4; };
// A and D's common initial sequence is A.a and D.d
struct E { unsigned int e; char b; };
// A and E's common initial sequence is empty
Member initialization
struct S
{
int n;
std::string s;
S() : n(7) // direct-initializes n, default-initializes s
{ }
};
int x = 0;
struct S
{
int n = ++x;
S() { } // uses default member initializer
S(int arg) : n(arg) { } // uses member initializer
};
int main()
{
std::cout << x << '\n'; // prints 0
S s1;
std::cout << x << '\n'; // prints 1 (default initializer ran)
S s2(7);
std::cout << x << '\n'; // prints 1 (default initializer did not run)
}
struct X {
int a[] = {1,2,3}; // error
int b[3] = {1,2,3}; // OK
};
struct node {
node* p = new node; // error: use of implicit or defaulted node::node()
};
struct A
{
A() = default; // OK
A(int v) : v(v) { } // OK
const int& v = 42; // OK
};
A a1; // error: ill-formed binding of temporary to reference
A a2(1); // OK (default member initializer ignored because v appears in a constructor)
// however a2.v is a dangling reference
struct S
{
int m;
int n;
int x = m; // OK: implicit this-> allowed in default initializers (C++11)
S(int i) : m(i), n(m) // OK: implicit this-> allowed in member initializer lists
{
this->f(); // explicit member access expression
f(); // implicit this-> allowed in member function bodies
}
void f();
};
struct S
{
int m;
void f();
};
int S::*p = &S::m; // OK: use of m to make a pointer to member
void (S::*fp)() = &S::f; // OK: use of f to make a pointer to member
Non-static member functions
#include <iostream>
#include <string>
#include <utility>
#include <exception>
struct S {
int data;
// simple converting constructor (declaration)
S(int val);
// simple explicit constructor (declaration)
explicit S(std::string str);
// const member function (definition)
virtual int getData() const { return data; }
};
// definition of the constructor
S::S(int val) : data(val) {
std::cout << "ctor1 called, data = " << data << '\n';
}
// this constructor has a catch clause
S::S(std::string str) try : data(std::stoi(str)) {
std::cout << "ctor2 called, data = " << data << '\n';
} catch(const std::exception&) {
std::cout << "ctor2 failed, string was '" << str << "'\n";
throw; // ctor's catch clause should always rethrow
}
struct D : S {
int data2;
// constructor with a default argument
D(int v1, int v2 = 11) : S(v1), data2(v2) {}
// virtual member function
int getData() const override { return data*data2; }
// lvalue-only assignment operator
D& operator=(D other) & {
std::swap(other.data, data);
std::swap(other.data2, data2);
return *this;
}
};
int main()
{
D d1 = 1;
S s2("2");
try {
S s3("not a number");
} catch(const std::exception&) {}
std::cout << s2.getData() << '\n';
D d2(3, 4);
d2 = d1; // OK: assignment to lvalue
// D(5) = d1; // ERROR: no suitable overload of operator=
}
class enclose {
class nested1; // forward declaration
class nested2; // forward declaration
class nested1 {}; // definition of nested class
};
class enclose::nested2 { }; // definition of nested class
class enclose {
struct nested { // private member
void g() {}
};
public:
static nested f() { return nested{}; }
};
int main()
{
//enclose::nested n1 = enclose::f(); // error: 'nested' is private
enclose::f().g(); // OK: does not name 'nested'
auto n2 = enclose::f(); // OK: does not name 'nested'
n2.g();
}
Derived classes
Virtual base classes
struct B { int n; };
class X : public virtual B {};
class Y : virtual public B {};
class Z : public B {};
// every object of type AA has one X, one Y, one Z, and two B's:
// one that is the base of Z and one that is shared by X and Y
struct AA : X, Y, Z {
AA() {
X::n = 1; // modifies the virtual B subobject's member
Y::n = 2; // modifies the same virtual B subobject's member
Z::n = 3; // modifies the non-virtual B subobject's member
std::cout << X::n << Y::n << Z::n << '\n'; // prints 223
}
};
struct B {
int n;
B(int x) : n(x) {}
};
struct X : virtual B { X() : B(1) {} };
struct Y : virtual B { Y() : B(2) {} };
struct AA : X, Y { AA() : B(3), X(), Y() {} };
// the default constructor of AA calls the default constructors of B , X and Y
// but those constructors do not call the constructor of B because B is a virtual base
AA a; // a.n == 3
// the default constructor of X calls the constructor of B
X x; // x.n == 1
class A{
public:
A(){
cout<<"call A\n";
}
};
class B:virtual public A{
public:
B(){
cout<<"call B\n";
}
};
class C:virtual public A{
public:
C(){
cout<<"call C\n";
}
};
class D: public B,public C{
public:
D(){
cout<<"call D\n";
}
};
int main()
{
D b;
}
output call A call B call C call D without virtual output call A call B call A call C call D
Using-declaration
#include <iostream>
struct B {
virtual void f(int) { std::cout << "B::f\n"; }
void g(char) { std::cout << "B::g\n"; }
void h(int) { std::cout << "B::h\n"; }
protected:
int m; // B::m is protected
typedef int value_type;
};
struct D : B {
using B::m; // D::m is public
using B::value_type; // D::value_type is public
using B::f;
void f(int) { std::cout << "D::f\n"; } // D::f(int) overrides B::f(int)
using B::g;
void g(int) { std::cout << "D::g\n"; } // both g(int) and g(char) are visible
// as members of D
using B::h;
void h(int) { std::cout << "D::h\n"; } // D::h(int) hides B::h(int)
};
int main()
{
D d;
B& b = d;
// b.m = 2; // error, B::m is protected
d.m = 1; // protected B::m is accessible as public D::m
b.f(1); // calls derived f()
d.f(1); // calls derived f()
d.g(1); // calls derived g(int)
d.g('a'); // calls base g(char)
b.h(1); // calls base h()
d.h(1); // calls derived h()
}
struct B1 { B1(int, ...) { } };
struct B2 { B2(double) { } };
int get();
struct D1 : B1 {
using B1::B1; // inherits B1(int, ...)
int x;
int y = get();
};
void test() {
D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
// then d.x is default-initialized (no initialization is performed),
// then d.y is initialized by calling get()
D1 e; // Error: D1 has no default constructor
}
struct D2 : B2 {
using B2::B2; // inherits B2(double)
B1 b;
};
D2 f(1.0); // error: B1 has no default constructor
struct A { A(int); };
struct B : A { using A::A; };
struct C1 : B { using B::B; };
struct C2 : B { using B::B; };
struct D1 : C1, C2 {
using C1::C1;
using C2::C2;
};
D1 d1(0); // ill-formed: constructor inherited from different B base subobjects
struct V1 : virtual B { using B::B; };
struct V2 : virtual B { using B::B; };
struct D2 : V1, V2 {
using V1::V1;
using V2::V2;
};
D2 d2(0); // OK: there is only one B subobject.
// This initializes the virtual B base class,
// which initializes the A base class
// then initializes the V1 and V2 base classes
// as if by a defaulted default constructor
virtual function specifier
struct A { virtual void f(); }; // A::f is virtual
struct B : A { void f(); }; // B::f overrides A::f in B
struct C : virtual B { void f(); }; // C::f overrides A::f in C
struct D : virtual B {}; // D does not introduce an overrider, B::f is final in D
struct E : C, D { // E does not introduce an overrider, C::f is final in E
using A::f; // not a function declaration, just makes A::f visible to lookup
};
int main() {
E e;
e.f(); // virtual call calls C::f, the final overrider in e
e.E::f(); // non-virtual call calls A::f, which is visible in E
}
class B {
virtual void do_f(); // private member
public:
void f() { do_f(); } // public interface
};
struct D : public B {
void do_f() override; // overrides B::do_f
};
int main()
{
D d;
B* bp = &d;
bp->f(); // internally calls D::do_f();
}
Virtual destructor
class Base {
public:
virtual ~Base() { /* releases Base's resources */ }
};
class Derived : public Base {
~Derived() { /* releases Derived's resources */ }
};
int main()
{
Base* b = new Derived;
delete b; // Makes a virtual function call to Base::~Base()
// since it is virtual, it calls Derived::~Derived() which can
// release resources of the derived class, and then calls
// Base::~Base() following the usual order of destruction
}
Covariant return types
class B {};
struct Base {
virtual void vf1();
virtual void vf2();
virtual void vf3();
virtual B* vf4();
virtual B* vf5();
};
class D : private B {
friend struct Derived; // in Derived, B is an accessible base of D
};
class A; // forward-declared class is an incomplete type
struct Derived : public Base {
void vf1(); // virtual, overrides Base::vf1()
void vf2(int); // non-virtual, hides Base::vf2()
// char vf3(); // Error: overrides Base::vf3, but has different
// and non-covariant return type
D* vf4(); // overrides Base::vf4() and has covariant return type
// A* vf5(); // Error: A is incomplete type
};
int main()
{
Derived d;
Base& br = d;
Derived& dr = d;
br.vf1(); // calls Derived::vf1()
br.vf2(); // calls Base::vf2()
// dr.vf2(); // Error: vf2(int) hides vf2()
B* p = br.vf4(); // calls Derived::vf4() and converts the result to B*
D* q = dr.vf4(); // calls Derived::vf4() and does not convert
// the result to B*
}
struct T1 { int mem; };
struct T2
{
int mem;
T2() { } // "mem" is not in the initializer list
};
int n; // static non-class, a two-phase initialization is done:
// 1) zero initialization initializes n to zero
// 2) default initialization does nothing, leaving n being zero
int main()
{
int n; // non-class, the value is indeterminate
std::string s; // class, calls default ctor, the value is "" (empty string)
std::string a[2]; // array, default-initializes the elements, the value is {"", ""}
// int& r; // error: a reference
// const int n; // error: a const non-class
// const T1 t1; // error: const class with implicit default ctor
T1 t1; // class, calls implicit default ctor
const T2 t2; // const class, calls the user-provided default ctor
// t2.mem is default-initialized (to indeterminate value)
}
struct T1
{
int mem1;
std::string mem2;
}; // implicit default constructor
struct T2
{
int mem1;
std::string mem2;
T2(const T2&) { } // user-provided copy constructor
}; // no default constructor
struct T3
{
int mem1;
std::string mem2;
T3() { } // user-provided default constructor
};
std::string s{}; // class => default-initialization, the value is ""
int main()
{
int n{}; // scalar => zero-initialization, the value is 0
double f = double(); // scalar => zero-initialization, the value is 0.0
int* a = new int[10](); // array => value-initialization of each element
// the value of each element is 0
T1 t1{}; // class with implicit default constructor =>
// t1.mem1 is zero-initialized, the value is 0
// t1.mem2 is default-initialized, the value is ""
// T2 t2{}; // error: class with no default constructor
T3 t3{}; // class with user-provided default constructor =>
// t3.mem1 is default-initialized to indeterminate value
// t3.mem2 is default-initialized, the value is ""
std::vector<int> v(3); // value-initialization of each element
// the value of each element is 0
std::cout << s.size() << ' ' << n << ' ' << f << ' ' << a[9] << ' ' << v[2] << '\n';
std::cout << t1.mem1 << ' ' << t3.mem1 << '\n';
delete[] a;
}
Direct initialization
Tobject( arg); Tobject( arg1, arg2, …);
Tobject{ arg};
T( other) T( arg1, arg2, …)
static_cast<T>(other)
newT(args, …)
Class::Class() : member(args, …) { … }
[arg](){ … }
struct B {
int a;
int&& r;
};
int f();
int n = 10;
B b1{1, f()}; // OK, lifetime is extended
B b2(1, f()); // well-formed, but dangling reference
B b3{1.0, 1}; // error: narrowing conversion
B b4(1.0, 1); // well-formed, but dangling reference
B b5(1.0, std::move(n)); // OK
struct M { };
struct L { L(M&); };
M n;
void f() {
M(m); // declaration, equivalent to M m;
L(n); // ill-formed declaration
L(l)(m); // still a declaration
}
Copy initialization
Tobject=other;
Tobject={other} ;
f(other)
returnother;
throw object;catch (Tobject)
Tarray[N] = {other};
struct A
{
operator int() { return 12;}
};
struct B
{
B(int) {}
};
int main()
{
std::string s = "test"; // OK: constructor is non-explicit
std::string s2 = std::move(s); // this copy-initialization performs a move
// std::unique_ptr<int> p = new int(1); // error: constructor is explicit
std::unique_ptr<int> p(new int(1)); // OK: direct-initialization
int n = 3.14; // floating-integral conversion
const int b = n; // const doesn't matter
int c = b; // ...either way
A a;
B b0 = 12;
// B b1 = a; //< error: conversion from 'A' to non-scalar type 'B' requested
B b2{a}; // < identical, calling A::operator int(), then B::B(int)
B b3 = {a}; // <
auto b4 = B{a}; // <
// b0 = a; //< error, assignment operator overload needed
}
Aggregate initialization
Tobject={arg1, arg2, …};
Tobject{arg1, arg2, …};
Tobject={.designator=arg1,.designator{arg2} … };
Tobject{.designator=arg1,.designator{arg2} … };
Tobject(arg1, arg2, …);
struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // error; designator order does not match declaration order
A b{.x = 1, .z = 2}; // ok, b.y initialized to 0
union u { int a; const char* b; };
u f = { .b = "asdf" }; // OK, active member of the union is b
u g = { .a = 1, .b = "asdf" }; // Error, only one initializer may be provided
struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2}; // valid C, invalid C++ (out of order)
int arr[3] = {[1] = 5}; // valid C, invalid C++ (array)
struct B b = {.a.x = 0}; // valid C, invalid C++ (nested)
struct A a = {.x = 1, 2}; // valid C, invalid C++ (mixed)
given Rfn(T&arg); or Rfn(T&&arg); fn(object)fn({arg1, arg2, …} )
inside T&fn() or T&&fn()returnobject;
given T&ref; or T&&ref; inside the definition of Class Class::Class(…):ref(object) {…}
struct S {
int mi;
const std::pair<int, int>& mp; // reference member
};
void foo(int) {}
struct A {};
struct B : A {
int n;
operator int&() { return n; }
};
B bar() { return B(); }
//int& bad_r; // error: no initializer
extern int& ext_r; // OK
int main() {
// Lvalues
int n = 1;
int& r1 = n; // lvalue reference to the object n
const int& cr(n); // reference can be more cv-qualified
volatile int& cv{n}; // any initializer syntax can be used
int& r2 = r1; // another lvalue reference to the object n
// int& bad = cr; // error: less cv-qualified
int& r3 = const_cast<int&>(cr); // const_cast is needed
void (&rf)(int) = foo; // lvalue reference to function
int ar[3];
int (&ra)[3] = ar; // lvalue reference to array
B b;
A& base_ref = b; // reference to base subobject
int& converted_ref = b; // reference to the result of a conversion
// Rvalues
// int& bad = 1; // error: cannot bind lvalue ref to rvalue
const int& cref = 1; // bound to rvalue
int&& rref = 1; // bound to rvalue
const A& cref2 = bar(); // reference to A subobject of B temporary
A&& rref2 = bar(); // same
int&& xref = static_cast<int&&>(n); // bind directly to n
// int&& copy_ref = n; // error: can't bind to an lvalue
double&& copy_ref = n; // bind to an rvalue temporary with value 1.0
// Restrictions on temporary lifetimes
std::ostream& buf_ref = std::ostringstream() << 'a'; // the ostringstream temporary
// was bound to the left operand of operator<<
// but its lifetime ended at the semicolon
// so buf_ref is a dangling reference
S a {1, {2, 3} }; // temporary pair {2, 3} bound to the reference member
// a.mp and its lifetime is extended to match a
S* p = new S{1, {2, 3} }; // temporary pair {2, 3} bound to the reference
// member p->mp, but its lifetime ended at the semicolon
// p->mp is a dangling reference
delete p;
}
examples
struct A{
A(int i){
}
};
struct B{
B(A a){
}
};
struct C{
C(B b){
}
};
int main(int argc,char* argv[]){
B b=(A)5;
B bb(5);
C c((A)5);
return 0;
}
using namespace std;
int fun(){
cout<<"call fun";
return 0;
}
typedef int (*ff)();
using fu=ff;
int main(int _argc,char* _argv[]){
int(*f)()=fun;
f();
(*f)();
ff fff=(ff)fun;
fu fu1=fun;
fu1();
}
class A{
public:
virtual int fun(){
cout<<"A";
return 0;
}
};
class B:public A{
public:
int fun() override {
cout<<"B";
return 0;
}
};
typedef int(A::*f)();
int main(int _argc,char* _argv[]){
f ff=&A::fun;
A a{};
B b{};
(a.*ff)();//A
(b.*ff)();//B
}
class A{
public:
int fun(){
cout<<"A";
return 0;
}
};
class B:public A{
public:
int fun() {
cout<<"B";
return 0;
}
};
typedef int(A::*f)();
int main(int _argc,char* _argv[]){
f ff=f(&B::fun);
A a{};
B b{};
(a.*ff)();//B
(b.*ff)();//B
}
you can not cast non virtual function pointer
class Foo{
public:
int f(char* c=0){
std::cout<<"Foo::f()"<<std::endl;
return 1;
}
};
class Bar{
public:
void b(int i=0){
std::cout<<"Bar::b()"<<std::endl;
}
};
class FooDerived:public Foo{
public:
int f(char* c=0){
std::cout<<"FooDerived::f()"<<std::endl;
return 1;
}
};
int main(int argc, char* argv[]){
typedef int (Foo::*FPTR) (char*);
typedef void (Bar::*BPTR) (int);
typedef int (FooDerived::*FDPTR) (char*);
FPTR fptr = &Foo::f;
BPTR bptr = &Bar::b;
FDPTR fdptr = &FooDerived::f;
//Bptr = static_cast<void (Bar::*) (int)> (fptr); //error
fdptr = static_cast<int (Foo::*) (char*)> (fptr); //OK: contravariance
Bar obj;
( obj.*(BPTR) fptr )(1);//call: Foo::f()
}
Output:
Foo::f()
you can cast virtual function pointer
class Foo{
public:
virtual int f(char* c=0){
std::cout<<"Foo::f()"<<std::endl;
return 1;
}
};
class Bar{
public:
virtual void b(int i=0){
std::cout<<"Bar::b()"<<std::endl;
}
};
class FooDerived:public Foo{
public:
int f(char* c=0){
std::cout<<"FooDerived::f()"<<std::endl;
return 1;
}
};
int main(int argc, char* argv[]){
typedef int (Foo::*FPTR) (char*);
typedef void (Bar::*BPTR) (int);
FPTR fptr=&Foo::f;
BPTR bptr=&Bar::b;
FooDerived objDer;
(objDer.*fptr)(0);//call: FooDerived::f(), not Foo::f()
Bar obj;
( obj.*(BPTR) fptr )(1);//call: Bar::b() , not Foo::f()
}
Output:
FooDerived::f()
Bar::b()
class A{
public:
void fun(){
cout<<"A";
}
};
class B:public A{
public:
void fun(){
cout<<"B";
}
};
int main(int _argc,char* _argv[]){
typedef void (A::*f)();
f f1=(f)&B::fun;
B b;
(b.*f1)();// if B did not inherit A (b.*(void (B::*)())f1)();
}
generic function pointer
template<class T>
void fun(void(T::*f)(int)){
T t;
(t.*f)(12);
}
class A{
public:
void fun(int i){
cout<<i;
}
};
int main(int argc,char* argv[]){
fun(&A::fun);
return 0;
}
template<int i,typename T>
int iter(T t){
return i-1;
}
template<typename T>
struct A{
T t;
};
template<typename T>
using fun= int(*)(T t);
template <typename T>
using attr=T A<T>::*;
int main(int argc, char *argv[])
{
QCoreApplication a(argc,argv);
fun<int> f=iter<2,int>;
attr<int> at=&A<int>::t;
return a.exec();
}
[&]{}; // OK: by-reference capture default
[&, i]{}; // OK: by-reference capture, except i is captured by copy
[&, &i] {}; // Error: by-reference capture when by-reference is the default
[&, this] {}; // OK, equivalent to [&]
[&, this, i]{}; // OK, equivalent to [&, i]
[=]{}; // OK: by-copy capture default
[=, &i]{}; // OK: by-copy capture, except i is captured by reference
[=, *this]{}; // until C++17: Error: invalid syntax
// since c++17: OK: captures the enclosing S2 by copy
[=, this] {}; // until C++20: Error: this when = is the default
// since C++20: OK, same as [=]
auto fun=[](int i)->int {return i;};
std::function<int(int)> fun2=fun;
int(*fun3)(int)=fun;
cout<<fun2(4);
class S {
int x = 0;
void f() {
int i = 0;
// auto l1 = [i, x]{ use(i, x); }; // error: x is not a variable
auto l2 = [i, x=x]{ use(i, x); }; // OK, copy capture
i = 1; x = 1; l2(); // calls use(0,0)
auto l3 = [i, &x=x]{ use(i, x); }; // OK, reference capture
i = 2; x = 2; l3(); // calls use(1,2)
}
};
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
int main()
{
std::vector<int> c = {1, 2, 3, 4, 5, 6, 7};
int x = 5;
c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; }), c.end());
std::cout << "c: ";
std::for_each(c.begin(), c.end(), [](int i){ std::cout << i << ' '; });
std::cout << '\n';
// the type of a closure cannot be named, but can be inferred with auto
// since C++14, lambda could own default arguments
auto func1 = [](int i = 6) { return i + 4; };
std::cout << "func1: " << func1() << '\n';
// like all callable objects, closures can be captured in std::function
// (this may incur unnecessary overhead)
std::function<int(int)> func2 = [](int i) { return i + 4; };
std::cout << "func2: " << func2(6) << '\n';
}
Function Declaration
Return type deduction
int x = 1;
auto f() { return x; } // return type is int
const auto& f() { return x; } // return type is const int&
auto f(bool val)
{
if (val) return 123; // deduces return type int
else return 3.14f; // error: deduces return type float
}
auto f() {} // returns void
auto g() { return f(); } // returns void
auto* x() {} // error: cannot deduce auto* from void
struct F
{
virtual auto f() { return 2; } // error virtual function cannot return type deduction
};
declarations examples
int a = 1, *p = NULL, f(), (*pf)(double);
// decl-specifier-seq is int
// declarator f() declares (but doesn't define)
// a function taking no arguments and returning int
struct S
{
virtual int f(char) const, g(int) &&; // declares two non-static member functions
virtual int f(char), x; // compile-time error: virtual (in decl-specifier-seq)
// is only allowed in declarations of non-static
// member functions
};
int f(int a, int *p, int (*(*x)(double))[3]);
int f(int a = 7, int *p = nullptr, int (*(*x)(double))[3] = nullptr);
int f(int, int *, int (*(*)(double))[3]);
int f(int = 7, int * = nullptr, int (*(*)(double))[3] = nullptr);
int main()
{
std::cout << "Test\n"; // There is no operator<< in global namespace, but ADL
// examines std namespace because the left argument is in
// std and finds std::operator<<(std::ostream&, const char*)
operator<<(std::cout, "Test\n"); // same, using function call notation
// however,
std::cout << endl; // Error: 'endl' is not declared in this namespace.
// This is not a function call to endl(), so ADL does not apply
endl(std::cout); // OK: this is a function call: ADL examines std namespace
// because the argument of endl is in std, and finds std::endl
(endl)(std::cout); // Error: 'endl' is not declared in this namespace.
// The sub-expression (endl) is not a function call expression
}
using std::swap;
swap(obj1, obj2);
namespace A {
struct X;
struct Y;
void f(int);
void g(X);
}
namespace B {
void f(int i) {
f(i); // calls B::f (endless recursion)
}
void g(A::X x) {
g(x); // Error: ambiguous between B::g (ordinary lookup)
// and A::g (argument-dependent lookup)
}
void h(A::Y y) {
h(y); // calls B::h (endless recursion): ADL examines the A namespace
// but finds no A::h, so only B::h from ordinary lookup is used
}
}
Overload Resolution
struct B { void f(int); };
struct A { operator B&(); };
A a;
a.B::f(1); // Error: user-defined conversions cannot be applied
// to the implicit object parameter
static_cast<B&>(a).f(1); // OK
int f1(int);
int f2(float);
struct A {
using fp1 = int(*)(int);
operator fp1() { return f1; } // conversion function to pointer to function
using fp2 = int(*)(float);
operator fp2() { return f2; } // conversion function to pointer to function
} a;
int i = a(1); // calls f1 via pointer returned from conversion function
struct A {
operator int(); // user-defined conversion
};
A operator+(const A&, const A&); // non-member user-defined operator
void m()
{
A a, b;
a + b; // member-candidates: none
// non-member candidates: operator+(a,b)
// built-in candidates: int(a) + int(b)
// overload resolution chooses operator+(a,b)
}
struct Y { operator int*(); }; // Y is convertible to int*
int *a = Y() + 100.0; // error: no operator+ between pointer and double
Viable functions
struct A { A(int); };
struct B { B(A); };
B b{ {0} }; // list-init of B
// candidates: B(const B&), B(B&&), B(A)
// {0} -> B&& not viable: would have to call B(A)
// {0} -> const B&: not viable: would have to bind to rvalue, would have to call B(A)
// {0} -> A viable. Calls A(int): user-defined conversion to A is not banned
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
};
A x (1, 2, 3); // uses #3, generated from a non-template constructor
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
A b2 = a; // uses #7 to deduce A<A<int>> and #1 to initialize
void Fcn(const int*, short); // overload #1
void Fcn(int*, int); // overload #2
int i;
short s = 0;
void f()
{
Fcn(&i, 1L); // 1st argument: &i -> int* is better than &i -> const int*
// 2nd argument: 1L -> short and 1L -> int are equivalent
// calls Fcn(int*, int)
Fcn(&i,'c'); // 1st argument: &i -> int* is better than &i -> const int*
// 2nd argument: 'c' -> int is better than 'c' -> short
// calls Fcn(int*, int)
Fcn(&i, s); // 1st argument: &i -> int* is better than &i -> const int*
// 2nd argument: s -> short is better than s -> int
// no winner, compilation error
}
Ranking of implicit conversion sequences
struct Base {};
struct Derived : Base {} d;
int f(Base&); // overload #1
int f(Derived&); // overload #2
int i = f(d); // d -> Derived& has rank Exact Match
// d -> Base& has rank Conversion
// calls f(Derived&)
int i;
int f1();
int g(const int&); // overload #1
int g(const int&&); // overload #2
int j = g(i); // lvalue int -> const int& is the only valid conversion
int k = g(f1()); // rvalue int -> const int&& better than rvalue int -> const int&
int f(void(&)()); // overload #1
int f(void(&&)()); // overload #2
void g();
int i1 = f(g); // calls #1
int f(const int &); // overload #1
int f(int &); // overload #2 (both references)
int g(const int &); // overload #1
int g(int); // overload #2
int i;
int j = f(i); // lvalue i -> int& is better than lvalue int -> const int&
// calls f(int&)
int k = g(i); // lvalue i -> const int& ranks Exact Match
// lvalue i -> rvalue int ranks Exact Match
// ambiguous overload: compilation error
int f(const int*);
int f(int*);
int i;
int j = f(&i); // &i -> int* is better than &i -> const int*, calls f(int*)
struct A {
operator short(); // user-defined conversion function
} a;
int f(int); // overload #1
int f(float); // overload #2
int i = f(a); // A -> short, followed by short -> int (rank Promotion)
// A -> short, followed by short -> float (rank Conversion)
// calls f(int)
Implicit conversion sequence in list-initialization
void f(int (&&)[] ); // overload #1
void f(double (&&)[] ); // overload #2
void f(int (&&)[2]); // overload #3
f({1}); // #1: Better than #2 due to conversion, better than #3 due to bounds
f({1.0}); // #2: double -> double is better than double -> int
f({1.0, 2.0}); // #2: double -> double is better than double -> int
f({1, 2}); // #3: -> int[2] is better than -> int[],
// and int -> int is better than int -> double
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
g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4
}
struct A { A(std::initializer_list<int>); };
void f(A);
struct B { B(int, double); };
void g(B);
g({'a','b'}); // calls g(B(int,double)), user-defined conversion
// g({1.0, 1,0}); // error: double->int is narrowing, not allowed in list-init
void f(B);
// f({'a','b'}); // f(A) and f(B) both user-defined conversions
struct A { int m1; double m2;};
void f(A);
f({'a','b'}); // calls f(A(int,double)), user-defined conversion
a = b a += b a -= b a *= b a /= b a %= b a &= b a |= b a ^= b a <<= b a >>= b
++a –a a++ a–
+a -a a + b a – b a * b a / b a % b ~a a & b a | b a ^ b a << b a >> b
!a a && b a || b
a == b a != b a < b a > b a <= b a >= b a <=> b
a[b] *a &a a->b a.b a->*b a.*b
a(…) a, b ? :
static_cast converts one type to another related type dynamic_cast converts within inheritance hierarchies const_cast adds or removes cv qualifiers reinterpret_cast converts type to unrelated type C-style cast converts one type to another by a mix of static_cast, const_cast, and reinterpret_cast new creates objects with dynamic storage duration delete destructs objects previously created by the new expression and releases obtained memory area sizeof queries the size of a type sizeof… queries the size of a parameter pack (since C++11) typeid queries the type information of a type noexcept checks if an expression can throw an exception (since C++11) alignof queries alignment requirements of a type (since C++11)
(since C++20) && || ++ — , ->* -> ( ) [ ]
std::string str = "Hello, ";
str.operator+=("world"); // same as str += "world";
operator<<(operator<<(std::cout, str) , '\n'); // same as std::cout << str << '\n';
// (since C++17) except for sequencing
assignment operator
T& operator=(const T& other) // copy assignment
{
if (this != &other) { // self-assignment check expected
if (other.size != size) { // storage cannot be reused
delete[] mArray; // destroy storage in this
size = 0;
mArray = nullptr; // preserve invariants in case next line throws
mArray = new int[other.size]; // create storage in this
size = other.size;
}
std::copy(other.mArray, other.mArray + other.size, mArray);
}
return *this;
}
T& operator=(T&& other) noexcept // move assignment
{
if(this != &other) { // no-op on self-move-assignment (delete[]/size=0 also ok)
delete[] mArray; // delete this storage
mArray = std::exchange(other.mArray, nullptr); // leave moved-from in valid state
size = std::exchange(other.size, 0);
}
return *this;
}
T& T::operator=(T arg) noexcept // copy/move constructor is called to construct arg
{
std::swap(size, arg.size); // resources are exchanged between *this and arg
std::swap(mArray, arg.mArray);
return *this;
}
example
class Fraction
{
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
int n, d;
public:
Fraction(int n, int d = 1) : n(n/gcd(n, d)), d(d/gcd(n, d)) { }
int num() const { return n; }
int den() const { return d; }
Fraction& operator*=(const Fraction& rhs)
{
int new_n = n * rhs.n/gcd(n * rhs.n, d * rhs.d);
d = d * rhs.d/gcd(n * rhs.n, d * rhs.d);
n = new_n;
return *this;
}
};
std::ostream& operator<<(std::ostream& out, const Fraction& f)
{
return out << f.num() << '/' << f.den() ;
}
bool operator==(const Fraction& lhs, const Fraction& rhs)
{
return lhs.num() == rhs.num() && lhs.den() == rhs.den();
}
bool operator!=(const Fraction& lhs, const Fraction& rhs)
{
return !(lhs == rhs);
}
Fraction operator*(Fraction lhs, const Fraction& rhs)
{
return lhs *= rhs;
}
int main()
{
Fraction f1(3, 8), f2(1, 2), f3(10, 2);
std::cout << f1 << " * " << f2 << " = " << f1 * f2 << '\n'
<< f2 << " * " << f3 << " = " << f2 * f3 << '\n'
<< 2 << " * " << f1 << " = " << 2 * f1 << '\n';
}
Address of an overloaded function
int f(int) { return 1; }
int f(double) { return 2; }
void g( int(&f1)(int), int(*f2)(double) ) {}
template< int(*F)(int) >
struct Templ {};
struct Foo {
int mf(int) { return 3; }
int mf(double) { return 4; }
};
struct Emp {
void operator<<(int (*)(double)) {}
};
int main()
{
// 1. initialization
int (*pf)(double) = f; // selects int f(double)
int (&rf)(int) = f; // selects int f(int)
int (Foo::*mpf)(int) = &Foo::mf; // selects int mf(int)
// 2. assignment
pf = nullptr;
pf = &f; // selects int f(double)
// 3. function argument
g(f, f); // selects int f(int) for the 1st argument
// and int f(double) for the second
// 4. user-defined operator
Emp{} << f; //selects int f(double)
// 5. return value
auto foo = []() -> int (*)(int) {
return f; // selects int f(int)
};
// 6. cast
auto p = static_cast<int(*)(int)>(f); // selects int f(int)
// 7. template argument
Templ<f> t; // selects int f(int)
}
enum A{
One=0,
Two=1,
Three=3
};
class AA{
public:
enum A{
One=0,
Two=1,
Three=3
};
};
int main(int _argc,char* _argv[]){
int l=::A::One;
l=::One;
::A a=(::A)1;
AA::A aa=AA::One;
aa=AA::A::One;
}
enum num : char { one = '0' };
std::cout << num::one; // '0', not 48
enum Foo { a, b, c = 10, d, e = 1, f, g = f + c };
//a = 0, b = 1, c = 10, d = 11, e = 1, f = 2, g = 12
Array
int a[2]; // array of 2 int
int* p1 = a; // a decays to a pointer to the first element of a
int b[2][3]; // array of 2 arrays of 3 int
// int** p2 = b; // error: b does not decay to int**
int (*p2)[3] = b; // b decays to a pointer to the first 3-element row of b
int c[2][3][4]; // array of 2 arrays of 3 arrays of 4 int
// int*** p3 = c; // error: c does not decay to int***
int (*p3)[3][4] = c; // c decays to a pointer to the first 3 × 4-element plane of c
int l[]{1,2,3,4,5,6,7};//or = {1,2,3,4,5,6,7};
int m=*(l+4);
//l++ ++l errors
int* k=new int[5]{1,2,3,4,5};
void g(int (&a)[3])
{
std::cout << a[0] << '\n';
}
void f(int* p)
{
std::cout << *p << '\n';
}
int main()
{
int a[3] = {1, 2, 3};
int* p = a;
std::cout << sizeof a << '\n' // prints size of array
<< sizeof p << '\n'; // prints size of a pointer
// where arrays are acceptable, but pointers aren't, only arrays may be used
g(a); // okay: function takes an array by reference
// g(p); // error
for(int n: a) // okay: arrays can be used in range-for loops
std::cout << n << ' '; // prints elements of the array
// for(int n: p) // error
// std::cout << n << ' ';
// where pointers are acceptable, but arrays aren't, both may be used:
f(a); // okay: function takes a pointer
f(p); // okay: function takes a pointer
std::cout << *a << '\n' // prints the first element
<< *p << '\n' // same
<< *(a + 1) << ' ' << a[1] << '\n' // prints the second element
<< *(p + 1) << ' ' << p[1] << '\n'; // same
}
Namespace
namespace Q {
namespace V { // original-namespace-definition for V
void f(); // declaration of Q::V::f
}
void V::f() {} // OK
void V::g() {} // Error: g() is not yet a member of V
namespace V { // extension-namespace-definition for V
void g(); // declaration of Q::V::g
}
}
namespace R { // not a enclosing namespace for Q
void Q::V::g() {} // Error: cannot define Q::V::g inside R
}
void Q::V::g() {} // OK: global namespace encloses Q
namespace D {
int d1;
void f(char);
}
using namespace D; // introduces D::d1, D::f, D::d2, D::f,
// E::e, and E::f into global namespace!
int d1; // OK: no conflict with D::d1 when declaring
namespace E {
int e;
void f(int);
}
namespace D { // namespace extension
int d2;
using namespace E; // transitive using-directive
void f(int);
}
void f() {
d1++; // error: ambiguous ::d1 or D::d1?
::d1++; // OK
D::d1++; // OK
d2++; // OK, d2 is D::d2
e++; // OK: e is E::e due to transitive using
f(1); // error: ambiguous: D::f(int) or E::f(int)?
f('a'); // OK: the only f(char) is D::f(char)
}
namespace vec {
template< typename T >
class vector {
// ...
};
} // of vec
int main()
{
std::vector<int> v1; // Standard vector.
vec::vector<int> v2; // User defined vector.
v1 = v2; // Error: v1 and v2 are different object's type.
{
using namespace std;
vector<int> v3; // Same as std::vector
v1 = v3; // OK
}
{
using vec::vector;
vector<int> v4; // Same as vec::vector
v2 = v4; // OK
}
return 0;
}
namespace foo {
namespace bar {
namespace baz {
int qux = 42;
}
}
}
namespace fbz = foo::bar::baz;
int main()
{
std::cout << fbz::qux << '\n';
}
Reference declaration
int& a[3]; // error
int&* p; // error
int& &r; // error
typedef int& lref;
typedef int&& rref;
int n;
lref& r1 = n; // type of r1 is int&
lref&& r2 = n; // type of r2 is int&
rref& r3 = n; // type of r3 is int&
rref&& r4 = 1; // type of r4 is int&&
void f(int& x) {
std::cout << "lvalue reference overload f(" << x << ")\n";
}
void f(const int& x) {
std::cout << "lvalue reference to const overload f(" << x << ")\n";
}
void f(int&& x) {
std::cout << "rvalue reference overload f(" << x << ")\n";
}
int main() {
int i = 1;
const int ci = 2;
f(i); // calls f(int&)
f(ci); // calls f(const int&)
f(3); // calls f(int&&)
// would call f(const int&) if f(int&&) overload wasn't provided
f(std::move(i)); // calls f(int&&)
// rvalue reference variables are lvalues when used in expressions
int&& x = 1;
f(x); // calls f(int& x)
f(std::move(x)); // calls f(int&& x)
}
forwarding
template<class T>
int f(T&& x) { // x is a forwarding reference
return g(std::forward<T>(x)); // and so can be forwarded
}
int main() {
int i;
f(i); // argument is lvalue, calls f<int&>(int&), std::forward<int&>(x) is lvalue
f(0); // argument is rvalue, calls f<int>(int&&), std::forward<int>(x) is rvalue
}
template<class T>
int g(const T&& x); // x is not a forwarding reference: const T is not cv-unqualified
template<class T> struct A {
template<class U>
A(T&& x, U&& y, int* p); // x is not a forwarding reference: T is not a
// type template parameter of the constructor,
// but y is a forwarding reference
};
Pointer
pointer to object
struct C {
int x, y;
} c;
int* px = &c.x; // value of px is "pointer to c.x"
int* pxe= px + 1; // value of pxe is "pointer past the end of c.x"
int* py = &c.y; // value of py is "pointer to c.y"
assert(pxe == py); // == tests if two pointers represent the same address
// may or may not fire
*pxe = 1; // undefined behavior even if the assertion does not fire
int n;
int* np = &n; // pointer to int
int* const* npp = &np; // non-const pointer to const pointer to non-const int
int a[2];
int (*ap)[2] = &a; // pointer to array of int
struct S { int n; };
S s = {1};
int* sp = &s.n; // pointer to the int that is a member of s
int n;
int* p = &n; // pointer to n
int& r = *p; // reference is bound to the lvalue expression that identifies n
r = 7; // stores the int 7 in n
std::cout << *p; // lvalue-to-rvalue implicit conversion reads the value from n
int a[2];
int* p1 = a; // pointer to the first element a[0] (an int) of the array a
int b[6][3][8];
int (*p2)[3][8] = b; // pointer to the first element b[0] of the array b,
// which is an array of 3 arrays of 8 ints
struct Base {};
struct Derived : Base {};
Derived d;
Base* p = &d;
const pointer
Syntax
meaning
const T*
pointer to constant object
T const*
pointer to constant object
T* const
constant pointer to object
const T* const
constant pointer to constant object
T const* const
constant pointer to constant object
const int* const i=new int ;
const int* const* ii=&i;//non-const pointer to const pointer to const object
const int n1=12;
const int* n2=&n1;//int* is error
pointer to void
int n = 1;
int* p1 = &n;
void* pv = p1;
int* p2 = static_cast<int*>(pv);
std::cout << *p2 << '\n'; // prints 1
pointer to functions
int (* f)()
f is a pointer to a function with prototype int func().
int (* f())()
f is a function taking no inputs and returning a pointer to a function with prototype int func().
int * f()
f is a function returning a pointer-to-int.
int (* a[])()
a is an array of pointers to functions each with prototype int func().
int (* f())[]
f is a function returning a pointer to an array.
int (f[])()
Not allowed. Can’t have an array of functions.
int * const *(*g)(float)
g is pointer to a function with prototype int * const * func(float) where its return value int * const * is a pointer to a read-only pointer-to-int.
int f();
int (*p)() = f; // pointer p is pointing to f
int (&r)() = *p; // the lvalue that identifies f is bound to a reference
r(); // function f invoked through lvalue reference
(*p)(); // function f invoked through the function lvalue
p();
Pointers to data members
struct C { int m; };
int main()
{
int C::* p = &C::m; // pointer to data member m of class C
C c = {7};
std::cout << c.*p << '\n'; // prints 7
C* cp = &c;
cp->m = 10;
std::cout << cp->*p << '\n'; // prints 10
}
struct Base { int m; };
struct Derived : Base {};
int main()
{
int Base::* bp = &Base::m;
int Derived::* dp = bp;
Derived d;
d.m = 1;
std::cout << d.*dp << ' ' << d.*bp << '\n'; // prints 1 1
}
struct A
{
int m;
// const pointer to non-const member
int A::* const p;
};
int main()
{
// non-const pointer to data member which is a const pointer to non-const member
int A::* const A::* p1 = &A::p;
const A a = {1, &A::m};
std::cout << a.*(a.*p1) << '\n'; // prints 1
// regular non-const pointer to a const pointer-to-member
int A::* const* p2 = &a.p;
std::cout << a.**p2 << '\n'; // prints 1
}
Pointers to function members
struct Base
{
void f(int n) { std::cout << n << '\n'; }
};
struct Derived : Base {};
int main()
{
void (Base::* bp)(int) = &Base::f;
void (Derived::* dp)(int) = bp;
Derived d;
(d.*dp)(1);
(d.*bp)(2);
}
struct Base {};
struct Derived : Base
{
void f(int n) { std::cout << n << '\n'; }
};
int main()
{
void (Derived::* dp)(int) = &Derived::f;
void (Base::* bp)(int) = static_cast<void (Base::*)(int)>(dp);
Derived d;
(d.*bp)(1); // okay: prints 1
Base b;
(b.*bp)(2); // undefined behavior
}
null pointer
To initialize a pointer to null or to assign the null value to an existing pointer, the null pointer literal nullptr, the null pointer constant NULL, or the implicit conversion from the integer value 0 may be used.
const and volatile and Mutable
int main()
{
int n1 = 0; // non-const object
const int n2 = 0; // const object
int const n3 = 0; // const object (same as n2)
volatile int n4 = 0; // volatile object
const struct
{
int n1;
mutable int n2;
} x = {0, 0}; // const object with mutable member
n1 = 1; // ok, modifiable object
// n2 = 2; // error: non-modifiable object
n4 = 3; // ok, treated as a side-effect
// x.n1 = 4; // error: member of a const object is const
x.n2 = 4; // ok, mutable member of a const object isn't const
const int& r1 = n1; // reference to const bound to non-const object
// r1 = 2; // error: attempt to modify through reference to const
const_cast<int&>(r1) = 2; // ok, modifies non-const object n1
const int& r2 = n2; // reference to const bound to const object
// r2 = 2; // error: attempt to modify through reference to const
// const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2
}
class Test {
public:
int x;
mutable int y;
Test() { x = 4; y = 10; }
};
int main()
{
const Test t1;
t1.y = 20;
cout << t1.y;
return 0;
}
class Customer
{
char name[25];
mutable char placedorder[50];
int tableno;
mutable int bill;
public:
Customer(char* s, char* m, int a, int p)
{
strcpy(name, s);
strcpy(placedorder, m);
tableno = a;
bill = p;
}
void changePlacedOrder(char* p) const
{
strcpy(placedorder, p);
}
void changeBill(int s) const
{
bill = s;
}
void display() const
{
cout << "Customer name is: " << name << endl;
cout << "Food ordered by customer is: " << placedorder << endl;
cout << "table no is: " << tableno << endl;
cout << "Total payable amount: " << bill << endl;
}
};
constexpr specifier
The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.
#include <iostream>
#include <stdexcept>
// C++11 constexpr functions use recursion rather than iteration
// (C++14 constexpr functions may use local variables and loops)
constexpr int factorial(int n)
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
// literal class
class conststr {
const char* p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}
// constexpr functions signal errors by throwing exceptions
// in C++11, they must do so from the conditional operator ?:
constexpr char operator[](std::size_t n) const
{
return n < sz ? p[n] : throw std::out_of_range("");
}
constexpr std::size_t size() const { return sz; }
};
// C++11 constexpr functions had to put everything in a single return statement
// (C++14 doesn't have that requirement)
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
std::size_t c = 0)
{
return n == s.size() ? c :
'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
countlower(s, n + 1, c);
}
// output function that requires a compile-time constant, for testing
template<int n>
struct constN
{
constN() { std::cout << n << '\n'; }
};
int main()
{
std::cout << "4! = " ;
constN<factorial(4)> out1; // computed at compile time
volatile int k = 8; // disallow optimization using volatile
std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time
std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
constN<countlower("Hello, world!")> out2; // implicitly converted to conststr
}
decltype
struct A { double x; };
const A* a;
decltype(a->x) y; // type of y is double (declared type)
decltype((a->x)) z = y; // type of z is const double& (lvalue expression)
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters
// return type can be deduced since C++14
{
return t+u;
}
int main()
{
int i = 33;
decltype(i) j = i * 2;
std::cout << "i = " << i << ", "
<< "j = " << j << '\n';
auto f = [](int a, int b) -> int
{
return a * b;
};
decltype(f) g = f; // the type of a lambda function is unique and unnamed
i = f(2, 2);
j = g(3, 3);
std::cout << "i = " << i << ", "
<< "j = " << j << '\n';
}
auto
#include <iostream>
#include <utility>
template<class T, class U>
auto add(T t, U u) { return t + u; } // the return type is the type of operator+(T, U)
// perfect forwarding of a function call must use decltype(auto)
// in case the function it calls returns by reference
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
template<auto n> // C++17 auto parameter declaration
auto f() -> std::pair<decltype(n), decltype(n)> // auto can't deduce from brace-init-list
{
return {n, n};
}
int main()
{
auto a = 1 + 2; // type of a is int
auto b = add(1, 1.2); // type of b is double
static_assert(std::is_same_v<decltype(a), int>);
static_assert(std::is_same_v<decltype(b), double>);
auto c0 = a; // type of c0 is int, holding a copy of a
decltype(auto) c1 = a; // type of c1 is int, holding a copy of a
decltype(auto) c2 = (a); // type of c2 is int&, an alias of a
std::cout << "a, before modification through c2 = " << a << '\n';
++c2;
std::cout << "a, after modification through c2 = " << a << '\n';
auto [v, w] = f<0>(); //structured binding declaration
std::cout<<v<<w;
auto d = {1, 2}; // OK: type of d is std::initializer_list<int>
auto n = {5}; // OK: type of n is std::initializer_list<int>
// auto e{1, 2}; // Error as of C++17, std::initializer_list<int> before
auto m{5}; // OK: type of m is int as of C++17, initializer_list<int> before
// decltype(auto) z = { 1, 2 } // Error: {1, 2} is not an expression
// auto is commonly used for unnamed types such as the types of lambda expressions
auto lambda = [](int x) { return x + 3; };
// auto int x; // valid C++98, error as of C++11
// auto x; // valid C, error in C++
}
decltype(auto)
in generic code you want to be able to perfectly forward a return type without knowing whether you are dealing with a reference or a value. decltype(auto) gives you that ability:
int i;
int&& f();
auto x3a = i; // decltype(x3a) is int
decltype(auto) x3d = i; // decltype(x3d) is int
auto x4a = (i); // decltype(x4a) is int
decltype(auto) x4d = (i); // decltype(x4d) is int&
auto x5a = f(); // decltype(x5a) is int
decltype(auto) x5d = f(); // decltype(x5d) is int&&
auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto *x7a = &i; // decltype(x7a) is int*
decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)
Delaying return type deduction in recursive templates
template<int i>
struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i>
constexpr auto iter(Int<i>) -> decltype(auto)
{ return iter(Int<i-1>{}); }
int main() { decltype(iter(Int<10>{})) a; }
Elaborated type
enum A { A_START = 0 };
void A(enum A a) {}
int main() {
enum A a;
A( a );
}
template <typename T>
struct Node {
struct Node* Next; // OK: lookup of Node finds the injected-class-name
struct Data* Data; // OK: declares type Data at global scope
// and also declares the data member Data
friend class ::List; // error: cannot introduce a qualified name
enum Kind* kind; // error: cannot introduce an enum
};
Data* p; // OK: struct Data has been declared