-2

I'm writing code where I'm creating multiple aliases for primitive types, e.g. Address and Id being ints.

I want to avoid using Addresses and Ids together, e.g. in arithmetic operations.

Thus I would like to have type-checking on these aliases, so that the following result can be obtained:

typedef int A;
typedef int B;

A f(A a) { return a+a; };

int main()
{
  A a = 5;
  B b = 5;
  f(a);     // I would like this to work...
  f(b);     // and this not to compile.
}

Now this does not work, but I know I can use a wrapper struct/class with just one member:

class A { public: int x; A(int xx) { x = xx; }};
class B { public: int x; B(int xx) { x = xx; }};

A f(A a) { return A(a.x+a.x); }; // this is ugly and I'd want to be able to use: return a+a

int main()
{
  A a = 5;
  B b = 5;
  f(a);     // This will work...
  f(b);     // This won't compile...
}

My question is - what's the best way I can get code working like the 2nd snippet, but without having to explicitly getting x all the time and construct new objects (as noted in the line with the "this is ugly" comment)?

I guess I can overload all relevant operators for all my 'aliases' but that's a lot of work and I'm hoping there's a faster/nicer solution.

Thanks.

PS To make this a concrete SO question, not a discussion: I'm just asking for a different way of achieving the result I want, than overloading everything. Thank you.

Kuba
  • 193
  • 1
  • 6
  • 1
    `// this is ugly and I'd want to be able to use: return a+a` So, why not overload `operator int()`? [Example](https://ideone.com/VKA0DO). – Algirdas Preidžius Sep 13 '17 at 22:23
  • 1
    So is it OK to add two IDs? Should the result be an ID again? What about multiplication, would you want to get ID squared? – n. m. could be an AI Sep 13 '17 at 22:26
  • 1
    see also https://stackoverflow.com/questions/34287842/c-strongly-typed-using-and-typedef et al. – underscore_d Sep 13 '17 at 22:33
  • @AlgirdasPreidžius - Thanks so much. I was not aware you could do something like that. I suppose that will work for any primitive type? – Kuba Sep 13 '17 at 22:34
  • @n.m. Oh yeah, that's a valid point, Algirdas's solution makes no restrictions on nonsensical operations. I guess I will just overload the selected operators by hand. Thank you. – Kuba Sep 13 '17 at 22:37

1 Answers1

1

I don't know about the "best" way but one thing you can do is create one type that overloads all the relevant operators and takes an integral template parameter so you can differentiate your types with a number:

template<std::size_t ID>
class strongly_typed_int
{
public:
    explicit strongly_typed_int(int i = 0): i(i) {}

    // ...

    strongly_typed_int operator+(strongly_typed_int i) { /*...*/ }
    // etc...

private:
    int i;
};

using security_id = strongly_typed_int<0>;
using access_code = strongly_typed_int<1>;
// etc...
Galik
  • 47,303
  • 4
  • 80
  • 117