profisional bootstrapping circuit






in cmath is called tgamma
initializer_list
template< class T >
class initializer_list;
https://en.cppreference.com/w/cpp/utility/initializer_list
| size | returns the number of elements in the initializer list (public member function) |
| begin | returns a pointer to the first element (public member function) |
| end | returns a pointer to one past the last element (public member function) |
#include <iostream>
#include <vector>
#include <initializer_list>
template <class T>
struct S {
std::vector<T> v;
S(std::initializer_list<T> l) : v(l) {
std::cout << "constructed with a " << l.size() << "-element list\n";
}
void append(std::initializer_list<T> l) {
v.insert(v.end(), l.begin(), l.end());
}
std::pair<const T*, std::size_t> c_arr() const {
return {&v[0], v.size()}; // copy list-initialization in return statement
// this is NOT a use of std::initializer_list
}
};
template <typename T>
void templated_fn(T) {}
int main()
{
S<int> s = {1, 2, 3, 4, 5}; // copy list-initialization
s.append({6, 7, 8}); // list-initialization in function call
std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";
for (auto n : s.v)
std::cout << n << ' ';
std::cout << '\n';
std::cout << "Range-for over brace-init-list: \n";
for (int x : {-1, -2, -3}) // the rule for auto makes this ranged-for work
std::cout << x << ' ';
std::cout << '\n';
auto al = {10, 11, 12}; // special rule for auto
std::cout << "The list bound to auto has size() = " << al.size() << '\n';
// templated_fn({1, 2, 3}); // compiler error! "{1, 2, 3}" is not an expression,
// it has no type, and so T cannot be deduced
templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
templated_fn<std::vector<int>>({1, 2, 3}); // also OK
}using namespace std;
template<class T>
class A{
public:
template <std::size_t N>
A(const T (&t)[N]){//or &&t
cout<< t[0];
cout<<N;
}
};
int main(int argc,char* argv[]){
int arr[]={1,2};
A a({1,2});
return 0;
}tuple
pair is like tuple but with two elements first and second
https://en.cppreference.com/w/cpp/utility/tuple
#include <tuple>
#include <iostream>
#include <string>
#include <stdexcept>
std::tuple<double, char, std::string> get_student(int id)
{
if (id == 0) return std::make_tuple(3.8, 'A', "Lisa Simpson");
if (id == 1) return std::make_tuple(2.9, 'C', "Milhouse Van Houten");
if (id == 2) return std::make_tuple(1.7, 'D', "Ralph Wiggum");
throw std::invalid_argument("id");
}
int main()
{
auto student0 = get_student(0);
std::cout << "ID: 0, "
<< "GPA: " << std::get<0>(student0) << ", "
<< "grade: " << std::get<1>(student0) << ", "
<< "name: " << std::get<2>(student0) << '\n';
double gpa1;
char grade1;
std::string name1;
std::tie(gpa1, grade1, name1) = get_student(1);
std::cout << "ID: 1, "
<< "GPA: " << gpa1 << ", "
<< "grade: " << grade1 << ", "
<< "name: " << name1 << '\n';
// C++17 structured binding:
auto [ gpa2, grade2, name2 ] = get_student(2);
std::cout << "ID: 2, "
<< "GPA: " << gpa2 << ", "
<< "grade: " << grade2 << ", "
<< "name: " << name2 << '\n';
}std::tuple<int, int> foo_tuple()
{
return {1, -1}; // Error until N4387
return std::tuple<int, int>{1, -1}; // Always works
return std::make_tuple(1, -1); // Always works
}apply
int add(int first, int second) { return first + second; }
template<typename T>
T add_generic(T first, T second) { return first + second; }
auto add_lambda = [](auto first, auto second) { return first + second; };
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, std::tuple<Ts...> const& theTuple)
{
std::apply
(
[&os](Ts const&... tupleArgs)
{
os << '[';
std::size_t n{0};
((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
os << ']';
}, theTuple
);
return os;
}
int main()
{
// OK
std::cout << std::apply(add, std::pair(1, 2)) << '\n';
// Error: can't deduce the function type
// std::cout << std::apply(add_generic, std::make_pair(2.0f, 3.0f)) << '\n';
// OK
std::cout << std::apply(add_lambda, std::pair(2.0f, 3.0f)) << '\n';
// advanced example
std::tuple myTuple(25, "Hello", 9.31f, 'c');
std::cout << myTuple << '\n';
}move
std::move is used to indicate that an object t may be “moved from”, i.e. allowing the efficient transfer of resources from t to another object.
In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.
#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
std::string str = "Hello";
std::vector<std::string> v;
// uses the push_back(const T&) overload, which means
// we'll incur the cost of copying str
v.push_back(str);
std::cout << "After copy, str is \"" << str << "\"\n";
// uses the rvalue reference push_back(T&&) overload,
// which means no strings will be copied; instead, the contents
// of str will be moved into the vector. This is less
// expensive, but also means str might now be empty.
v.push_back(std::move(str));
std::cout << "After move, str is \"" << str << "\"\n";
std::cout << "The contents of the vector are \"" << v[0]
<< "\", \"" << v[1] << "\"\n";
}After copy, str is "Hello" After move, str is "" The contents of the vector are "Hello", "Hello"
forward
template<class T>
void wrapper(T&& arg)
{
// arg is always lvalue
foo(std::forward<T>(arg)); // Forward as lvalue or as rvalue, depending on T
}struct Arg
{
int i = 1;
int get() && { return i; } // call to this overload is rvalue
int& get() & { return i; } // call to this overload is lvalue
};#include <iostream>
#include <memory>
#include <utility>
struct A {
A(int&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
A(int& n) { std::cout << "lvalue overload, n=" << n << "\n"; }
};
class B {
public:
template<class T1, class T2, class T3>
B(T1&& t1, T2&& t2, T3&& t3) :
a1_{std::forward<T1>(t1)},
a2_{std::forward<T2>(t2)},
a3_{std::forward<T3>(t3)}
{
}
private:
A a1_, a2_, a3_;
};
template<class T, class U>
std::unique_ptr<T> make_unique1(U&& u)
{
return std::unique_ptr<T>(new T(std::forward<U>(u)));
}
template<class T, class... U>
std::unique_ptr<T> make_unique2(U&&... u)
{
return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}
int main()
{
auto p1 = make_unique1<A>(2); // rvalue
int i = 1;
auto p2 = make_unique1<A>(i); // lvalue
std::cout << "B\n";
auto t = make_unique2<B>(2, i, 3);
}rvalue overload, n=2 lvalue overload, n=1 B rvalue overload, n=2 lvalue overload, n=1 rvalue overload, n=3
exchange
template<class T, class U = T>
constexpr // since C++20
T exchange(T& obj, U&& new_value)
{
T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;
}swap
int main()
{
int a = 5, b = 3;
// before
std::cout << a << ' ' << b << '\n';
std::swap(a,b);
// after
std::cout << a << ' ' << b << '\n';
}bitset
set,reset,flip,size,all,any,none ~^|&
https://en.cppreference.com/w/cpp/utility/bitset
#include <bitset>
int main()
{
std::bitset<8> b1(42);
for (std::size_t i = 0; i < b1.size(); ++i) {
std::cout << "b1[" << i << "]: " << b1[i] << '\n';
}
b1[0] = true; // modifies the first bit through bitset::reference
std::cout << "After setting bit 0, the bitset holds " << b1 << '\n';
}type_traits
https://en.cppreference.com/w/cpp/header/type_traits
| Composite type categories | Primary type category |
|---|---|
is_arithmetic | is_floating_point or is_integral |
is_fundamental | is_arithmetic or is_void |
is_object | is_arithmetic or is_enum or is_pointer or is_member_pointer |
is_reference | is_lvalue_reference or is_rvalue_reference |
is_compound | complement of is_fundamental |
is_member_pointer | is_member_object_pointer or is_member_function_pointer |
template class Base, class Derived> | Checks if Derived is derived from Base. |
struct is_base_of | |
template <class From, class To> | Checks if From can be converted to To. |
struct is_convertible | |
template <class T, class U> | Checks if the types T and U are the same. |
struct is_same |
#include <type_traits>
using std::cout;
cout << std::is_void<void>::value; // true
cout << std::is_integral<short>::value; // true
cout << std::is_floating_point<double>::value; // true
cout << std::is_array<int [] >::value; // true
cout << std::is_pointer<int*>::value; // true
cout << std::is_reference<int&>::value; // true
struct A{
int a;
int f(int){ return 2011; }
};
cout << std::is_member_object_pointer<int A::*>::value; // true
cout << std::is_member_function_pointer<int (A::*)(int)>::value; // true
enum E{
e= 1,
};
cout << std::is_enum<E>::value; // true
union U{
int u;
};
cout << std::is_union<U>::value; // true
cout << std::is_class<std::string>::value; // true
cout << std::is_function<int * (double)>::value; // true
cout << std::is_lvalue_reference<int&>::value; // true
cout << std::is_rvalue_reference<int&&>::value; // true
cout << is_const<int>::value; // false
cout << is_const<const int>::value; // true
cout << is_const<add_const<int>::type>::value; // true
typedef add_const<int>::type myConstInt;
cout << is_const<myConstInt>::value; //true
typedef const int myConstInt2;
cout << is_same<myConstInt, myConstInt2>::value; // true
cout << is_same<int, remove_const<add_const<int>::type>::type>::value; // true
cout << is_same<const int, add_const<add_const<int>::type>::type>::value; // true
functional
https://en.cppreference.com/w/cpp/header/functional
...
#include <functional>
...
// for placehoder _1 and _2
using namespace std::placeholders; f
using std::bind;
using std::function
...
double divMe(double a, double b){ return a/b; };
function < double(double, double) > myDiv1= bind(divMe, _1, _2);
function < double(double) > myDiv2= bind(divMe, 2000, _1);
divMe(2000, 10) == myDiv1(2000, 10) == myDiv2(10);#include <functional>
...
using std::make_pair;
using std::map;
map<const char, std::function<double(double, double)>> tab;
tab.insert(make_pair('+', [](double a, double b){ return a + b; }));
tab.insert(make_pair('-', [](double a, double b){ return a - b; }));
tab.insert(make_pair('*', [](double a, double b){ return a * b; }));
tab.insert(make_pair('/', [](double a, double b){ return a / b; }));
std::cout << tab['+'](3.5, 4.5); // 8
std::cout << tab['-'](3.5, 4.5); // -1
std::cout << tab['*'](3.5, 4.5); // 15.75
std::cout << tab['/'](3.5, 4.5); // 0.777778| Function type | Return type | Type of the arguments |
|---|---|---|
double(double, double) | double | double |
int() | int | |
double(int, double) | double | int, double |
void() |
std::variant is a type-safe union. An instance of std::variant has a value from one of its types. The type must not be a reference, array or void.
#include <variant>
...
std::variant<int, float> v, w;
v = 12; // v contains int
int i = std::get<int>(v);
w = std::get<int>(v);
w = std::get<0>(v); // same effect as the previous line
w = v; // same effect as the previous line
// std::get<double>(v); // error: no double in [int, float]
// std::get<3>(v); // error: valid index values are 0 and 1
try{
std::get<float>(w); // w contains int, not float: will throw
}
catch (std::bad_variant_access&) {}
std::variant<std::string> v("abc"); // converting constructor must be unambiguous
v = "def"; // converting assignment must be unambiguousoptional
can have value or empty
#include <optional>
std::optional<int> getFirst(const std::vector<int>& vec){
if (!vec.empty()) return std::optional<int>(vec[0]);
else return std::optional<int>();
}
...
std::vector<int> myVec{1, 2, 3};
std::vector<int> myEmptyVec;
auto myInt= getFirst(myVec);
if (myInt){
std::cout << *myInt << std::endl; // 1
std::cout << myInt.value() << std::endl; // 1
std::cout << myInt.value_or(2017) << std::endl; // 1
}
auto myEmptyInt= getFirst(myEmptyVec);
if (!myEmptyInt){
std::cout << myEmptyInt.value_or(2017) << std::endl; // 2017
} std::any is a type-safe container for single values of any type which is copy-constructible.
#include <algorithm>
#include <any>
#include <iostream>
#include <string>
#include <vector>
class Star
{
std::string name;
int id;
public:
Star(std::string name, int id) : name { name }, id { id }
{
std::cout << "Star::Star(string, int)\n";
}
void print() const
{
std::cout << "Star{ \"" << name << "\" : " << id << " };\n";
}
};
auto main() -> int
{
std::any celestial;
// (1) emplace( Args&&... args );
celestial.emplace<Star>("Procyon", 2943);
const auto* star = std::any_cast<Star>(&celestial);
star->print();
std::any av;
// (2) emplace( std::initializer_list<U> il, Args&&... args );
av.emplace<std::vector<char>>({ 'C', '+', '+', '1', '7' } /* no args */ );
std::cout << av.type().name() << '\n';
const auto* va = std::any_cast<std::vector<char>>(&av);
std::for_each(va->cbegin(), va->cend(), [](char const& c) { std::cout << c; });
std::cout << '\n';
}#include <any>
struct MyClass{};
...
std::vector<std::any> anyVec{true, 2017, std::string("test"), 3.14, MyClass()};
std::cout << std::any_cast<bool>(anyVec[0]); // true
int myInt= std::any_cast<int>(anyVec[1]);
std::cout << myInt << std::endl; // 2017
std::cout << anyVec[0].type().name(); // b
std::cout << anyVec[1].type().name(); // iany a=any(12);
a.emplace<B>(B());
cout<<a.type().name();//1Bstatic_cast
Converts between types using a combination of implicit and user-defined conversions
#include <vector>
#include <iostream>
struct B {
int m = 0;
void hello() const {
std::cout << "Hello world, this is B!\n";
}
};
struct D : B {
void hello() const {
std::cout << "Hello world, this is D!\n";
}
};
enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };
int main()
{
// 1: initializing conversion
int n = static_cast<int>(3.14);
std::cout << "n = " << n << '\n';
std::vector<int> v = static_cast<std::vector<int>>(10);
std::cout << "v.size() = " << v.size() << '\n';
// 2: static downcast
D d;
B& br = d; // upcast via implicit conversion
br.hello();
D& another_d = static_cast<D&>(br); // downcast
another_d.hello();
// 3: lvalue to xvalue
std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
std::cout << "after move, v.size() = " << v.size() << '\n';
// 4: discarded-value expression
static_cast<void>(v2.size());
// 5. inverse of implicit conversion
void* nv = &n;
int* ni = static_cast<int*>(nv);
std::cout << "*ni = " << *ni << '\n';
// 6. array-to-pointer followed by upcast
D a[10];
B* dp = static_cast<B*>(a);
// 7. scoped enum to int or float
E e = E::ONE;
int one = static_cast<int>(e);
std::cout << one << '\n';
// 8. int to enum, enum to another enum
E e2 = static_cast<E>(one);
EU eu = static_cast<EU>(e2);
// 9. pointer to member upcast
int D::*pm = &D::m;
std::cout << br.*static_cast<int B::*>(pm) << '\n';
// 10. void* to any type
void* voidp = &e;
std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}dynamic_cast
Safely converts pointers and references to classes up, down, and sideways along the inheritance hierarchy
struct V {
virtual void f() {}; // must be polymorphic to use runtime-checked dynamic_cast
};
struct A : virtual V {};
struct B : virtual V {
B(V* v, A* a) {
// casts during construction (see the call in the constructor of D below)
dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B
}
};
struct D : A, B {
D() : B(static_cast<A*>(this), this) { }
};
struct Base {
virtual ~Base() {}
};
struct Derived: Base {
virtual void name() {}
};
int main()
{
D d; // the most derived object
A& a = d; // upcast, dynamic_cast may be used, but unnecessary
D& new_d = dynamic_cast<D&>(a); // downcast
B& new_b = dynamic_cast<B&>(a); // sidecast
Base* b1 = new Base;
if(Derived* d = dynamic_cast<Derived*>(b1))
{
std::cout << "downcast from b1 to d successful\n";
d->name(); // safe to call
}
Base* b2 = new Derived;
if(Derived* d = dynamic_cast<Derived*>(b2))
{
std::cout << "downcast from b2 to d successful\n";
d->name(); // safe to call
}
delete b1;
delete b2;
}const_cast
Converts between types with different cv-qualification.
struct type {
int i;
type(): i(3) {}
void f(int v) const {
// this->i = v; // compile error: this is a pointer to const
const_cast<type*>(this)->i = v; // OK as long as the type object isn't const
}
};
int main()
{
int i = 3; // i is not declared const
const int& rci = i;
const_cast<int&>(rci) = 4; // OK: modifies i
std::cout << "i = " << i << '\n';
type t; // if this was const type t, then t.f(4) would be undefined behavior
t.f(4);
std::cout << "type::i = " << t.i << '\n';
const int j = 3; // j is declared const
int* pj = const_cast<int*>(&j);
// *pj = 4; // undefined behavior
void (type::* pmf)(int) const = &type::f; // pointer to member function
// const_cast<void(type::*)(int)>(pmf); // compile error: const_cast does
// not work on function pointers
}user-defined conversion
Enables implicit conversion or explicit conversion from a class type to another type.
struct X {
//implicit conversion
operator int() const { return 7; }
// explicit conversion
explicit operator int*() const { return nullptr; }
// Error: array operator not allowed in conversion-type-id
// operator int(*)[3]() const { return nullptr; }
using arr_t = int[3];
operator arr_t*() const { return nullptr; } // OK if done through typedef
// operator arr_t () const; // Error: conversion to array not allowed in any case
};
class A{
public:
explicit A(int i){
}
};
int main()
{
X x;
int n = static_cast<int>(x); // OK: sets n to 7
int m = x; // OK: sets m to 7
int* p = static_cast<int*>(x); // OK: sets p to null
// int* q = x; // Error: no implicit conversion
int (*pa)[3] = x; // OK
A a=(A)12;
}Function templates
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;
}template <class T>
struct A{
template<class AA>
void fun();
};
template <class T>
template<class AA>
void A<T>::fun(){
}
template <>
template<>
void A<QString>::fun<QString>(){
}
template<>
struct A<int>{
void fun();
};
void A<int>::fun(){
}Non-type parameters for templates
#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 doubletemplate<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 <class T,class ...TT>
class AA;
template <class T,class ...TT>
class AA<T(TT...)>{
};abstract class
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 Abstract {
virtual void f() = 0; // pure virtual
virtual void g() {} // non-pure virtual
~Abstract() {
g(); // OK: calls Abstract::g()
// f(); // undefined behavior
Abstract::f(); // OK: non-virtual call
}
};
// definition of the pure virtual function
void Abstract::f() { std::cout << "A::f()\n"; }
struct Concrete : Abstract {
void f() override {
Abstract::f(); // OK: calls pure virtual function
}
void g() override {}
~Concrete() {
g(); // OK: calls Concrete::g()
f(); // OK: calls Concrete::f()
}
};override specifier
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
}Copy assignment operator
#include <iostream>
#include <memory>
#include <string>
#include <algorithm>
struct A
{
int n;
std::string s1;
// user-defined copy assignment, copy-and-swap form
A& operator=(A other)
{
std::cout << "copy assignment of A\n";
std::swap(n, other.n);
std::swap(s1, other.s1);
return *this;
}
};
struct B : A
{
std::string s2;
// implicitly-defined copy assignment
};
struct C
{
std::unique_ptr<int[]> data;
std::size_t size;
// non-copy-and-swap assignment
C& operator=(const C& other)
{
// check for self-assignment
if(&other == this)
return *this;
// reuse storage when possible
if(size != other.size)
{
data.reset(new int[other.size]);
size = other.size;
}
std::copy(&other.data[0], &other.data[0] + size, &data[0]);
return *this;
}
// note: copy-and-swap would always cause a reallocation
};
int main()
{
A a1, a2;
std::cout << "a1 = a2 calls ";
a1 = a2; // user-defined copy assignment
B b1, b2;
b2.s1 = "foo";
b2.s2 = "bar";
std::cout << "b1 = b2 calls ";
b1 = b2; // implicitly-defined copy assignment
std::cout << "b1.s1 = " << b1.s1 << " b1.s2 = " << b1.s2 << '\n';
}Move constructors
#include <string>
#include <iostream>
#include <iomanip>
#include <utility>
struct A
{
std::string s;
int k;
A() : s("test"), k(-1) { }
A(const A& o) : s(o.s), k(o.k) { std::cout << "move failed!\n"; }
A(A&& o) noexcept :
s(std::move(o.s)), // explicit move of a member of class type
k(std::exchange(o.k, 0)) // explicit move of a member of non-class type
{ }
};
A f(A a)
{
return a;
}
struct B : A
{
std::string s2;
int n;
// implicit move constructor B::(B&&)
// calls A's move constructor
// calls s2's move constructor
// and makes a bitwise copy of n
};
struct C : B
{
~C() { } // destructor prevents implicit move constructor C::(C&&)
};
struct D : B
{
D() { }
~D() { } // destructor would prevent implicit move constructor D::(D&&)
D(D&&) = default; // forces a move constructor anyway
};
int main()
{
std::cout << "Trying to move A\n";
A a1 = f(A()); // return by value move-constructs the target from the function parameter
std::cout << "Before move, a1.s = " << std::quoted(a1.s) << " a1.k = " << a1.k << '\n';
A a2 = std::move(a1); // move-constructs from xvalue
std::cout << "After move, a1.s = " << std::quoted(a1.s) << " a1.k = " << a1.k << '\n';
std::cout << "Trying to move B\n";
B b1;
std::cout << "Before move, b1.s = " << std::quoted(b1.s) << "\n";
B b2 = std::move(b1); // calls implicit move constructor
std::cout << "After move, b1.s = " << std::quoted(b1.s) << "\n";
std::cout << "Trying to move C\n";
C c1;
C c2 = std::move(c1); // calls copy constructor
std::cout << "Trying to move D\n";
D d1;
D d2 = std::move(d1);
}Move assignment operator
#include <string>
#include <iostream>
#include <utility>
struct A
{
std::string s;
A() : s("test") { }
A(const A& o) : s(o.s) { std::cout << "move failed!\n"; }
A(A&& o) : s(std::move(o.s)) { }
A& operator=(const A& other)
{
s = other.s;
std::cout << "copy assigned\n";
return *this;
}
A& operator=(A&& other)
{
s = std::move(other.s);
std::cout << "move assigned\n";
return *this;
}
};
A f(A a) { return a; }
struct B : A
{
std::string s2;
int n;
// implicit move assignment operator B& B::operator=(B&&)
// calls A's move assignment operator
// calls s2's move assignment operator
// and makes a bitwise copy of n
};
struct C : B
{
~C() { } // destructor prevents implicit move assignment
};
struct D : B
{
D() { }
~D() { } // destructor would prevent implicit move assignment
D& operator=(D&&) = default; // force a move assignment anyway
};
int main()
{
A a1, a2;
std::cout << "Trying to move-assign A from rvalue temporary\n";
a1 = f(A()); // move-assignment from rvalue temporary
std::cout << "Trying to move-assign A from xvalue\n";
a2 = std::move(a1); // move-assignment from xvalue
std::cout << "Trying to move-assign B\n";
B b1, b2;
std::cout << "Before move, b1.s = \"" << b1.s << "\"\n";
b2 = std::move(b1); // calls implicit move assignment
std::cout << "After move, b1.s = \"" << b1.s << "\"\n";
std::cout << "Trying to move-assign C\n";
C c1, c2;
c2 = std::move(c1); // calls the copy assignment operator
std::cout << "Trying to move-assign D\n";
D d1, d2;
d2 = std::move(d1);
}Converting constructor
struct A
{
A() { } // converting constructor (since C++11)
A(int) { } // converting constructor
A(int, int) { } // converting constructor (since C++11)
};
struct B
{
explicit B() { }
explicit B(int) { }
explicit B(int, int) { }
};
int main()
{
A a1 = 1; // OK: copy-initialization selects A::A(int)
A a2(2); // OK: direct-initialization selects A::A(int)
A a3{4, 5}; // OK: direct-list-initialization selects A::A(int, int)
A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
A a5 = (A)1; // OK: explicit cast performs static_cast, direct-initialization
// B b1 = 1; // error: copy-initialization does not consider B::B(int)
B b2(2); // OK: direct-initialization selects B::B(int)
B b3{4, 5}; // OK: direct-list-initialization selects B::B(int, int)
// B b4 = {4, 5}; // error: copy-list-initialization selected an explicit constructor
// B::B(int, int)
B b5 = (B)1; // OK: explicit cast performs static_cast, direct-initialization
B b6; // OK, default-initialization
B b7{}; // OK, direct-list-initialization
// B b8 = {}; // error: copy-list-initialization selected an explicit constructor
// B::B()
}class A{
public:
void fun()&{
cout<<"can called only by lvalue";
}
void fun()&&{
cout<<"can called only by rvalue";
}
};