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

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);

No comments: