Useful C++11 features

The following are some features that added to the C++11 standard and are useful in programming.

auto

At the compile-time type of variable is deduced from the initializer. There is no need to declare the type of variable.

In following example vector<int>::iterator is replaced with auto.

#include <iostream>
#include <vector>
using namespace std;

double add(int a, int b) {
  double c = a + b;
  return c;
}
int main() {
  vector<int> vec = {1, 2, 3, 4, 5};
  auto a = 1;            // type of a is int
  auto b = 1.1;          // type of b is float
  auto c = add(123, 46); // type of c is double
  auto d = 'a';          // type of d is char
  auto e = vec.begin();  // type of e is vector<int>::iterator
  auto &a1 = a;          // type of a1 is reference to int
  int sum = 0;
  for (auto i = vec.begin(); i != vec.end(); i++) {
    sum += *i;
  }
  cout << "sum of elements is " << sum << "\n";
}

We can see the code is more readable. We can also get variables by reference by auto& instead of auto.

range based for loop

With help of range based for loop can be written as

#include <iostream>
#include <vector>
using namespace std;
int main() {
  vector<int> vec = {1, 2, 3, 4, 5};
  int sum = 0;
  for (auto i:vec) {
    sum += i;
  }
  cout << "sum of elements is " << sum << "\n";
}

lambda

Lambda is an unnamed function object capable of capturing variables in scope.

Lambda syntax: [capture clause] (parameter list) {lambda body}

Capture clause meaning
[ ] (…){..} Access no variables
[=] (…){..} Capture variables by value
[&] (…){..} Capture variables by reference
[n, &m] (…){..} For each variable, decide capture type (value or reference)

The following code shows each capture example.

#include <iostream>
using namespace std;
int main() {
  // lambda to print value
  auto print = [](int a) { std::cout << "printing: " << a << "\n"; };
  print(1234);   // print 1234

  // lambda to add values
  auto add = [](int a, int b) { return a + b; };
 cout << "5 + 3 = " << add(5, 3) << "\n"; //  5 + 3 = 8

  int n = 10;
  int m = 12;
  // capture variables by value
  auto printValue = [=]() { std::cout << "n = " << n << "\n"; };
  printValue(); //  n = 10

  // capture variables by reference
  auto printRef = [&]() { std::cout << "n = " << n << "\n"; };
  printRef(); // n = 10

  // capture individual variable
  auto printPass = [n, &m]() { // capture n by value, m by reference
    std::cout << "n = " << n << "\n"
              << "m = " << m << "\n";
  };
  printPass(); // n = 10 m = 12
  return 0;
}

Variables capture by value can not be modified inside the lambda using the mutable keyword allows modification inside the lambda.

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
using namespace std;

int main() {
  int n = 10;
  // modify value in lambda
  std::cout << "n = " << n << "\n"; // n = 10
  // auto incN = [=]() { n++; }; // error can not assign in non-mutable lambda
  auto incN = [=]() mutable { n++; };
  incN();
  std::cout << "n = " << n << "\n"; // n = 10
  return 0;
}

Lambda is convenient to use with standard library algorithms.

The following is an example of sorting elements of a vector by absolute values.

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
using namespace std;

int main() {
  std::vector<int> v = {-1, 3, 76, 9, 5, 3, 55, 7, -4, -7, -9, -1};
  // sort vector by absolute value
  std::sort(v.begin(), v.end(), [](int a, int b) { return abs(a) < abs(b); });
  for (auto &i : v) {
    std::cout << i << " "; // -1 -1 3 3 -4 5 7 -7 9 -9 55 76
  }

  return 0;
}

trailing return type

C++11 introduced a new way to declare the return value of a function. This new way is useful in lambda and template programming.

#include <iostream>
using namespace std;

// trailing return type function example
auto mul(int a, int b) -> int { return a * b; }

int main() {
  std::cout << mul(2, 4) << "\n";

  // use of trailing return type in lambda
  auto add = [](int a, int b) -> int { return a + b; };
  return 0;
}

decltype

Using template and lambda with auto sometimes it is difficult to deduce the return type without knowing the argument types, in this situation decltype becomes useful. decltype returns type of variable or expression

#include <iostream>
#include <string>
using namespace std;
// use of decltype in template
template <typename A, typename B> 
auto add(A a, B b) -> decltype(a + b) {
  return a + b;
}
int main() {
  int a = 1;
  decltype(a) b = a * 5; // declare variable b of same type as a

  cout << add(4, 6) << "\n";     // return int
  cout << add(4, 6.1) << "\n";   // return float
  cout << add(4.1, 6) << "\n";   // return float
  cout << add(4.1, 6.1) << "\n"; // return float

  auto mul = [](int a, int b) -> int { return a * b; };
  decltype(mul) newMul = mul; // the type of a lambda is unique and unnamed
  cout << mul(2, 4) << "\n";
  cout << newMul(2, 5) << "\n";
  return 0;
}

override

C++11 introduced the new keyword override, which at compile time checks whether the method overridden is virtual in parent class, if not then it throw the error. It act as safety check at compile time, whether overridden method is virtual or not in parent class.

#include <iostream>
#include <string>
using namespace std;

class A {
public:
  A() {}
  virtual ~A() {}
  virtual void method1() { cout << "method1 A\n"; }
  void method2() { cout << "method2 A\n"; }
};

class B : A {
public:
  B() {}
  virtual ~B() {}
  void method1() override { cout << "method1 B\n"; }; // OK
  void
  method2() { // error only virtual functions can be marked override
    cout << "method2 B\n";
  };
};

final

‘final’ ensures when used in virtual function declaration or definition that marked function can not be overridden into the derived class otherwise compile time error is generated.

‘final’ ensures when used in class definition that no class can be derived from that class otherwise compile time error is generated.

class Base {
public:
  virtual void foo() {}
};

class A : Base {
  void foo() final{}; // mark method as final
  void bar() final{}; // error as it is non virtual method
};

class B final : A {      // make class final
  void foo() override{}; // error foo overrides final function
};

class C : B { // error class B is marked as final
};

Reference

  1. cppreference.com
  2. stroustrup C++ FAQ