text: // Copyright (C) 2016-2019 Jonathan Müller <jonathanmueller.dev@gmail.com>
  // This file is subject to the license terms in the LICENSE file
  // found in the top-level directory of this distribution.
  
  #include <iostream>
  #include <string>
  #include <unordered_set>
  
  #include <type_safe/strong_typedef.hpp>
  
  namespace ts = type_safe;
  
  // we want some kind of handle to an int
  struct handle : ts::strong_typedef<handle, int*>,                   // required
                  ts::strong_typedef_op::equality_comparison<handle>, // for operator==/operator!=
                  ts::strong_typedef_op::dereference<handle, int>     // for operator*/operator->
  {
      using strong_typedef::strong_typedef;
  
      // we also want the operator bool()
      explicit operator bool() const noexcept
      {
          return static_cast<int*>(*this) != nullptr;
      }
  };
  
  void use_handle(handle h)
  {
      // we can dereference it
      std::cout << *h << '\n';
  
      // and compare it
      (void)(h == handle(nullptr));
  
      // and reassign
      int a;
      h = handle(&a);
      // or get back
      int* ptr = static_cast<int*>(h);
      std::cout << &a << ' ' << ptr << '\n';
  }
  
  // integer representing a distance
  struct distance
  : ts::strong_typedef<distance, unsigned>,                 // required
    ts::strong_typedef_op::equality_comparison<distance>,   // for operator==/operator!=
    ts::strong_typedef_op::relational_comparison<distance>, // for operator< etc.
    ts::strong_typedef_op::integer_arithmetic<distance> // all arithmetic operators that make sense
                                                        // for integers
  {
      using strong_typedef::strong_typedef;
  };
  
  // we want to output it
  std::ostream& operator<<(std::ostream& out, const distance& d)
  {
      return out << static_cast<unsigned>(d) << " distance";
  }
  
  namespace std
  {
  // we want to use it with the std::unordered_* containers
  template <>
  struct hash<::distance> : type_safe::hashable<::distance>
  {};
  
  } // namespace std
  
  int main()
  {
      distance d(4);
      //    int      val = d; // error
      //    d += 3;           // error
      d += distance(3); // works
  
      std::unordered_set<distance> set{d};
  
      std::cout << *set.find(d) << '\n';
  }
  