Sparrow - C++ Type Checker

Define a better C++ copy/move semantics for your classes and structures

Let's start with a problem.

#include <iostream>
#include <utility>

struct Person {
  Person(int a) : age(a) {}
  int age = -1;
};

int main() {
  Person p1(40);
  Person p2 = std::move(p1);
  std::cout << "Age of Person 1: " << p1.age << " years" << std::endl;
  std::cout << "Age of Person 2: " << p2.age << " years" << std::endl;
}

What do you think is the output of the above program?

Oh, why is the age still showing 40 when we have moved the p1 using std::move(p1)?

As the age is an integer - a POD data type, the default move constructor can't change its value, leaving p1 in an undefined state post move! How do you handle this? By having a manually defined move constructor and resetting the age to -1!

Now, let us look at the below code snippet -

#include <iostream>
#include <utility>

struct Person {
  Person(int a) : age(a) {}
  Person(Person&& rhs) {
    age = std::move(rhs.age);
    rhs.age = -1;
  }

  int age = -1;
};

int main() {
  Person p1(40);
  Person p2 = std::move(p1);
  std::cout << "Age of Person 1: " << p1.age << " years" << std::endl;
  std::cout << "Age of Person 2: " << p2.age << " years" << std::endl;
}

With this change, the output is now correct as -

We want to ensure the move/copy semantics are prescribed to such classes/structs! With this problem in hand, I wanted to design a type checker system around these trivial, default, or deleted move/copy semantics for C++ objects!

This is how the type checker library - sparrow - was born

https://github.com/vivekgalatage/sparrow.

With this library in place, you can enforce the classes to follow specific patterns with copy/move semantics. The above code will now become -

#include "sparrow.h"

struct Person {
  Person(int a) : age(a) {}
  Person(Person&& rhs) {
    age = std::move(rhs.age);
    rhs.age = -1;
  }

  int age = -1;
};

int main() {
  using TypeChecker =
      sparrow::TypeChecker<Person, sparrow::kCustomMoveConstructor>;
  constexpr TypeChecker c1;
  Person p1(42);
  Person p2 = std::move(p1);
  return 0;
}

Now, when the author tries to remove the manually defined move constructor, the compiler will throw an error as -

#include "sparrow.h"

struct Person {
  Person(int a) : age(a) {}
  // Missing the manually defined move constructor
  int age = -1;
};

int main() {
  using TypeChecker =
      sparrow::TypeChecker<Person, sparrow::kCustomMoveConstructor>;
  constexpr TypeChecker c1;
  Person p1(42);
  Person p2 = std::move(p1);
  return 0;
}

=============================================

error: static_assert failed due to requirement 'custom_move_constructor()'

Do let me know your feedback on the GitHub repository URL via issues!

Happy coding!

Did you find this article valuable?

Support Vivek Galatage by becoming a sponsor. Any amount is appreciated!