3

I have used BOOST_STRONG_TYPEDEF before, mainly with std::string and I got satisfactory results:

#include <boost/serialization/strong_typedef.hpp>
#include <iostream>

BOOST_STRONG_TYPEDEF(std::string, TIMER_ID)
BOOST_STRONG_TYPEDEF(std::string, PROCESS_ID)

int main()
{
    TIMER_ID t_id("Timer");
    PROCESS_ID p_id("Process");

    if (t_id == p_id)
        std::cout << "They are equal!" << std::endl;
}

The previous code fails to compile as expected:

In file included from /usr/include/boost/serialization/strong_typedef.hpp:26:0,
                 from types.cpp:1:
/usr/include/boost/operators.hpp: In instantiation of ‘bool boost::operator==(const std::__cxx11::basic_string<char>&, const PROCESS_ID&)’:
types.cpp:12:14:   required from here
/usr/include/boost/operators.hpp:144:64: error: no match for ‘operator==’ (operand types are ‘const PROCESS_ID’ and ‘const std::__cxx11::basic_string<char>’)
      friend bool operator==(const U& y, const T& x) { return x == y; }

However, this code compiles just fine:

#include <boost/serialization/strong_typedef.hpp>
#include <iostream>

BOOST_STRONG_TYPEDEF(unsigned int, TIMER_ID)
BOOST_STRONG_TYPEDEF(unsigned int, PROCESS_ID)

int main()
{
    TIMER_ID t_id(12);
    PROCESS_ID p_id(12);

    if (t_id == p_id)
    {
        std::cout << "They are equal!" << std::endl;
        std::cout << "Their sum is " << t_id + p_id << std::endl;
    }
}

This doesn't seem strong at all! I would expect to not be able to compare or add objects of two different types without a static_cast.

  • Why is this happening?
  • How can one accomplish type safety with primitive types without manually creating classes for each type?
user2891462
  • 3,033
  • 2
  • 32
  • 60
  • 2
    We use Matthew Wilson's 'true typedef' from CUJ: http://www.drdobbs.com/true-typedefs/184401633. See also this discussion https://stackoverflow.com/questions/23726038/how-can-i-create-a-new-primitive-type-using-c11-style-strong-typedefs and http://boost-users.boost.narkive.com/XVDlErPB/boost-strong-typedef. – gast128 Nov 27 '17 at 14:27

1 Answers1

4
#include <cassert>
#include "NamedType/named_type.hpp"

int main() {
  using TIMER_ID =
      fluent::NamedType<unsigned int, struct TimerIdTag, fluent::Comparable>;
  using PROCESS_ID =
      fluent::NamedType<unsigned int, struct ProcessIdTag, fluent::Comparable>;

  TIMER_ID a(123);
  PROCESS_ID b(456);

  assert(a == a);
  // assert(a == b); doesn't compile
  return 0;
}
Dorian
  • 490
  • 2
  • 10