essay on programming languages, computer science, information techonlogies and all.

Thursday, April 19, 2018

C++ template tutorial with code example

Parameterized Type


template < typename T >
class Vector 
{
private:
  T* elem;
  int sz;

public:
  explicit Vector(int s) 
  {
    elem = new T[s];
    sz = s;
  }

  T& operator[](int i) 
  {
    if (i < 0 || i >= size()) throw out_of_range("[i] is out of bound");
    return elem[i]; 
  }
};

{
  Vector< int > vi(200);
  vi[0] = 123;
  assert(vi[0] == 123);
}

{
  Vector< string > vs(17);
  vs[3] = "Hello";
  assert(vs[3] == "Hello");
}

{
  Vector< vector < int > > vli(45);
  vli[4] = vector({ 1, 2, 3 });
  assert(vli[4][1] == 2);
}

Function Template


template< typename T >
class Vector {
  // ...

  T* begin() const { return size() ? elem : nullptr; }
  T* end() const { return begin() + size(); }
};

template< typename Container, typename Value >
Value sum(const Container& c, Value v)
{
  for (auto x : c) v += x;
  return v;
}

{
  Vector< int > vi(4);
  vi[0] = 0; vi[1] = 1; vi[2] = 2; vi[3] = 3;
  double ds = sum(vi, 0.0);  // summation to double
  assert(ds == 6.0);

  int is = sum(vi, 0);  // summation to int
  assert(is == 6);
}

{
  list< double > ld;
  ld.push_back(3.0); ld.push_back(4.0);

  double ds = sum(ld, 0.0);
  assert(ds == 7.0);
}

Function Object


class Shape 
{
public:
  virtual void draw() = 0;
  virtual void rotate( double degree ) = 0;
};

class Rect : public Shape 
{
public:
  void draw() { cout << "rect"; }
  void rotate(double degree) { cout << "rotate"; }
};

class Circle : public Shape 
{
public:
  void draw() { cout << "circle"; }
  void rotate(double degree) {}
};

template< typename C, typename Oper >
void for_all(C& c, Oper op)
{
  for (auto& x : c) op(x);
}

vector< unique_ptr< Shape > > v;
v.push_back(make_unique< Rect >());
v.push_back(make_unique< Circle >());

for_all(v, [](unique_ptr< Shape >& s){ s->draw(); });
for_all(v, [](unique_ptr< Shape >& s){ s->rotate(45); });

Variadic Templates


void foo() { cout << endl; }

template< typename T >
void bar(T x) { cout << x << " "; }

template < typename T, typename ...Tail >
void foo(T head, Tail... tail) 
{
  bar(head);
  foo(tail...);
}

foo(1, 2, 2, "Hello");
foo(0.2, 'c', "World!", 0, 1, 2);

Function Specialization


template < class T>
T MyMax(T a, T b) 
{  
  return a > b ? a : b; 
}

template < >
const char* MyMax(const char* a, const char* b)
{
  return strlen(a) > strlen(b) ? a : b;
}


assert(MyMax(1, 2) == 2);
assert(MyMax("Morning", "Afternoon") == "Afternoon");

Function Specialization - Example


struct IO {
  int addr; 
  bool state;
};

struct Servo {
  int axis;
  double position;
};

struct Verify {
  template< typename T >
  static void Equal( T arg ) { throw exception("Should specialize"); }

  static void Equal(IO io) {
    cout << "check addr " << io.addr << " to be " << io.state << endl;
  }

  static void Equal(Servo s) {
    cout << "check axis " << s.axis << " position is at " << s.position << endl;
  }
};

Verify::Equal(IO{ 41, true });
Verify::Equal(Servo{ 3, 3.141592 });

Template Class Specialization - CompileTimeAssert


template< bool > struct CompileTimeAssert;
template< > struct CompileTimeAssert< true > {};

// CompileTimeAssert< sizeof(uint32_t) == 2  >();
CompileTimeAssert< sizeof(uint32_t) == 4 >();

// CompileTimeAssert< std::is_base_of::value >();
CompileTimeAssert< std::is_base_of::value >();

static_assert(std::is_base_of< Shape, Rect >::value, “Rect is a Shape");

Template Class Specialization - TypeTrait


template< typename T >
  struct IsVoid {
  static const bool value = false;
};

template< >
  struct IsVoid< void >{
  static const bool value = true;
};

template< typename T >
  struct IsPointer{
  static const bool value = false;
};

template< typename T >
  struct IsPointer< T* >{
  static const bool value = true;
};

CompileTimeAssert< IsVoid< void >::value >();
// CompileTimeAssert< IsVoid< int >::value >();

CompileTimeAssert< IsPointer< Shape* >::value >();
// CompileTimeAssert< IsPointer< Shape >::value >();

static_assert( is_pointer< Shape* >::value, "Shape* should be a pointer");

smart pointer to release resource automatically


class FILEReleasePolicy
{
public:
 static void release(FILE* fp) { fclose(fp); }
};

using FILEPtr = Poco::SharedPtr;
{
  FILEPtr fp = fopen("temp.txt", "wt");
  fprintf(fp, "hello world");
}

Sunday, April 1, 2018

C++11,14 tutorial with code example

Initializer with default constructor

 struct Foo {
  int Bar; string Too;
 };

 Foo a = { 1234, "Hello" };
 // Foo b( 1234, "Hello" );   // compile error

 vector c = {
  { 1234, "Hello" },
  { 4321, "World" },
  { 1111, "Good Morning" }
 };
When defined a constructor, the default constructor can't be used.

 struct Foo {
  int Bar; string Too;
  Foo(int bar) : Bar(bar) {}
 };

 // Foo a = { 1234, "Hello" };   // compile error
 Foo b{ 1234 };   
 Foo c(1234);
std::initializer usage

 struct Foo {
  int sum(const std::initializer_list< int >& list) {
   int total = 0;
   for (auto& e : list) {
    total += e;
   }
   return total;
  }
 };
 Foo foo;

 auto list = { 1, 2, 3 };
 assert(foo.sum(list) == 6);
 assert(foo.sum({ 1, 2, 3 }) == 6);
 assert(foo.sum({}) == 0);
lvalue and rvalue

 int a = 42;
 int b = 43;

 // a and b are both l-values:
 a = b; // ok
 b = a; // ok
 a = a * b; // ok

 // a * b is an rvalue:
 int c = a * b; // ok, rvalue on right hand side of assignment
 // a * b = 42; // error C2106: '=' : left operand must be l-value
Function return is rvalue but can be lvalue if reference returned.

 int someValue = { 1212 };
 int& foo() { return someValue; }
 int foobar() { return someValue; }

 // lvalues:
 int i = 42;
 i = 43; // ok, i is an lvalue
 int* p = &i; // ok, i is an lvalue
 foo() = 42; // ok, foo() is an lvalue
 int* p1 = &foo(); // ok, foo() is an lvalue

 // rvalues:
 int j = 0;
 j = foobar(); // ok, foobar() is an rvalue
//  int* p2 = &foobar(); // error C2102: '&' requires l-value
 j = 1234; // ok, 42 is an rvalue
Resolving function when argument is reference and universal reference.

 struct FooA { int X = 1234; };
 FooA RunFooA(const FooA& a) { FooA temp = a; temp.X = 4321; return temp; }
 FooA RunFooA(FooA&& a) { a.X = 4321; return a; }


 FooA a;
 FooA b = RunFooA(a);
 FooA c = RunFooA(FooA());
 FooA d = RunFooA(std::move(a));
transfer ownership of std::unique_ptr using std::move

 std::unique_ptr p1{ new int };
// std::unique_ptr p2 = p1; // error -- cannot copy unique pointers
 std::unique_ptr p3 = std::move(p1); // move `p1` into `p2`
       // now unsafe to dereference object held by `p1`
auto type resolution

 auto a = 3.14; // double
 auto b = 1; // int
 auto& c = b; // int&
 auto d = { 0 }; // std::initializer_list
 auto&& e = 1; // int&&
 auto&& f = b; // int&
 auto g = new auto(123); // int*
 delete g;
 const auto h = 1; // const int
 auto i = 1, j = 2, k = 3; // int, int, int
 // auto l = 1, m = true, n = 1.61; // error -- `l` deduced to be int, `m` is bool
 // auto o; // error -- `o` requires initializer
no more typing iterator type

 std::vector v = { 1, 2, 3, 4 };
 std::vector::const_iterator cit1 = v.cbegin();
 auto cit2 = v.cbegin();
auto return type using decltype

 template 
 auto AddAnyTwo(X x, Y y) -> decltype(x + y) {
  return x + y;
 }


 assert(AddAnyTwo(1, 2) == 3);
 assert(AddAnyTwo(1, 2.0) == 3.0);
 assert(AddAnyTwo(1.5, 1.5) == 3.0);
lambda

 int LBar = 1;

 auto getLBar = [=]{ return LBar; };
 assert(getLBar() == 1);

 auto addLBar = [=](int y) { return LBar + y; };
 assert(addLBar(1) == 2);

 auto getLBarRef = [&]() -> int& { return LBar; };
 getLBarRef() = 2;
 assert(LBar == 2);
lambda capture - reference or not

 int x = 1;
 auto f1 = [&x] { x = 2; }; // OK: x is a reference and modifies the original
 f1();

 // auto f2 = [x] { x = 2; }; // ERROR: the lambda can only perform const-operations on the captured value
 auto f3 = [x]() mutable { x = 2; }; // OK: the lambda can perform any operations on the captured value
 f3();
using as alias

 template  using Vec = std::vector;

 Vec v{}; // std::vector

 using String = std::string;
 String s{ "foo" };
nullptr

 struct Foo
 {
  void Bar(int) {}
  void Bar(char*) {}
 };

 Foo foo;
 foo.Bar(NULL);  // should throw error but not with VS2013
 foo.Bar(nullptr);
unspecified enum is just a number

 enum Week { Monday = 0, Tuesday, Thursday };
 enum Month { January = 0, Feburary,  };

 Month m = January;

 if (m == Monday)
 {
  // danger !!!
  m = Feburary;
 }

// Specifying underlying type as `unsigned int`
 enum class Color : unsigned int { Red = 0xff0000, Green = 0xff00, Blue = 0xff };
  
 // `Red`/`Green` in `Alert` don't conflict with `Color`
 enum class Alert : bool { Red = false, Green };
  
 Color redColor = Color::Red;
 Alert redAlert = Alert::Red;

 // bool isSame = (redColor == redAlert); 
 // error C2678: binary '==' : no operator found which takes a left-hand operand of type 'CPPTest::testStrongTypedEnum::Color' 
 // (or there is no acceptable conversion)

delegating constructor

 struct Foo {
  int foo;
  Foo(int foo) : foo(foo) {}
  Foo() : Foo(1) {}
 };

 Foo foo{};
 assert( foo.foo == 1 );
be more explicit on function overriding

 struct A {
  virtual void foo() {}
  void bar() {}
 };

 struct B : A {
  void foo() override {};  // correct -- B::foo overrides A::foo
  // void bar() override {}; // error C3668 : 'CPPTest::testOverrides::B::bar' : method with override specifier 'override' did not override any base class methods
  // void baz() override {}; // error C3668 : 'CPPTest::testOverrides::B::baz' : method with override specifier 'override' did not override any base class methods
 };
say final to stop overriding

 struct A {
  virtual void foo() {}
 };

 struct B : A {
  virtual void foo() final {}
 };

 struct C : B {
  // virtual void foo() {} // error C3248: 'CPPTest::testFinal::B::foo': function declared as 'final' cannot be overridden by 'CPPTest::testFinal::C::foo'
 };
say final to stop inheritance

 struct A final {};

 // error C3246: 'CPPTest::testFinal1::B' : cannot inherit from 'CPPTest::testFinal1::A' as it has been declared as 'final'
 // struct B : A {};
delete to stop compiler generating default methods

#pragma warning( push )
#pragma warning( disable : 4822)

 class A {
  int x;

 public:
  A(int x) : x(x) {};
  A(const A&) = delete;
  A& operator=(const A&) = delete;
 };

 A x{ 123 };
 // A y = x; // error C2280: 'CPPTest::testDeletedFunction::A::testDeletedFunction::A(const CPPTest::testDeletedFunction::A &)' : attempting to reference a deleted function
 // y = x; // error -- operator= deleted

#pragma warning( pop )
range based iteration

 std::vector a{ 1, 2, 3, 4, 5 };
 for (int& x : a) 
 { 
  x *= 2; 
 }
 // a == { 2, 4, 6, 8, 10 }

 for (int x : a) 
 {
  x *= 2;
 }
 // a == { 2, 4, 6, 8, 10 }

 int b[] = { 5, 4, 3, 2, 1 };
 for (int& x : b)
 {
  x *= 3;
 }
std::to_string

 assertEqual("123", std::to_string(123));
 assertEqual("1.200000", std::to_string(1.2));
std::unique_ptr

 
 {
  std::unique_ptr p1{ new int };
  *p1 = 1234;
  assert(*p1 == 1234);
 }

 {
  int *p1 = new int;
  *p1 = 1234;
  assert(*p1 == 1234);
  delete p1;
 }
std::unique_ptr and struct

 
 struct Foo { int Bar; string Too; };
 std::unique_ptr p1{ new Foo };
 p1->Bar = 1234;
 p1->Too = "hello";

 assert(p1->Bar == 1234);
 assert(p1->Too == "hello");
std::make_unique

 struct Foo {
  Foo(int bar, string too) : Bar(bar), Too(too){}
  int Bar; string Too;
 };
 std::unique_ptr p1;

 if (p1 == nullptr)
 {
  // p1 = new Foo;  // compile error 
  p1 = std::unique_ptr(new Foo(1234, "Hello"));
  p1 = std::make_unique(1234, "Hello");
 }
unique_ptr to vector

 struct Foo {
  Foo(int bar, string too) : Bar(bar), Too(too){}
  int Bar; string Too;
 };
 vector< std::unique_ptr > Foos;
 Foos.push_back(std::unique_ptr(new Foo(1234, "Hello")));
 Foos.push_back(std::make_unique(4321, "World"));
 Foos.push_back(std::make_unique(1111, "Good Morning"));
std::shared_ptr

 struct Foo { int Bar = 1234; string Too = "Hello"; };
 std::shared_ptr p1{ new Foo };
 p1->Bar = 4321;

 std::shared_ptr p2 = p1;
 p2->Too = "World";

 assertEqual("World", p1->Too);

 auto p3 = make_shared();
 assertEqual(1234, p3->Bar);

 p1 = p3;
unique_ptr to shared_ptr

 struct Foo { int Bar = 1234; string Too = "Hello"; };
 std::unique_ptr p1( new Foo );

 // std::shared_ptr p2 = p1; 
 // error C2440 : 'initializing' : cannot convert from 'std::unique_ptr< CPPTest::testSharedPtr1::Foo,std::default_delete <_Ty> >' 
 // to 'std::shared_ptr'

 std::shared_ptr p3 = std::move(p1); 

 // p1 is dangling now
tuple

 // `playerProfile` has type `std::tuple`.
 auto playerProfile = std::make_tuple(51, "Frans Nielsen", "NYI");
 assertEqual( 51, std::get<0>(playerProfile)); 
 assertEqual( "Frans Nielsen", std::get<1>(playerProfile));
 assertEqual( "NYI", std::get<2>(playerProfile)); 
tie

// With tuples...
 std::string playerName;
 std::tie(std::ignore, playerName, std::ignore) = std::make_tuple(91, "John Tavares", "NYI");
 assertEqual("John Tavares", playerName);

 // With pairs...
 std::string yes, no;
 std::tie(yes, no) = std::make_pair("yes", "no");
 assertEqual("yes", yes);
 assertEqual("no", no);