2

This question already has an answer here:

I would like to define several names for the same type and have the compiler distinguish between them.

My motivation is that different int variables could represent very different units, and I would like the compiler to catch errors in units.

typedef int Speed does not generate any warnings, when assigning to Speed from int. One possible solution is using an enum. Furthermore, the enum "hack" does not let me specify the underlying representation e.g. uint8_t.

Is what I am trying to do a bad practice? How do I achieve it in C++?


Edit:

Grim. I tied using enum Speed {};.

error: invalid conversion from 'int' to 'Speed' [-fpermissive] 
error: no match for 'operator+=' in 'a += b'

Those are just a couple of errors I encountered. Enums can't be the right way.

I will think about structs, and if in my case some members and predefined operators can actually make the rest of the code cleaner.

Hmm, here is quite some research, to the point of making my question a duplicate.

marked as duplicate by Bart van Ingen Schenau, user40980, GlenH7, gnat, mattnz Jun 27 '14 at 4:34

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    Not specific to C++, but could you not use a struct for this? e.g. (psuedo) struct Speed { int value };? – jimbobmcgee Jun 17 '14 at 16:36
  • @jimbobmcgee, that would work. However 1) users must type .value in addition to the name of the variable 2) is a bit of a WTF moment. I can't believe that a language this strict doesn't have an out-of-the-box solution. – Vorac Jun 17 '14 at 16:42
  • 1
    but you would write your public methods to only accept Speeds not ints, e.g. (psuedo) void move(Direction dir, Speed speed) { ... }, so they would have to pass the struct. Your method would have to know to use speed.value, the consumer would have to pass a fully-formed Speed struct. – jimbobmcgee Jun 17 '14 at 16:46
  • 2
    Have a look at the Boost library for units of measure – GlenH7 Jun 17 '14 at 16:47
  • @jimbobmcgee has it right - using structs is probably the way to go about that. This is how it's handled in the Boost library at least (not that you need to use Boost to solve this problem), but you can get some ideas from the library. – Chris Cirefice Jun 17 '14 at 17:33
1

You can't really do this in C++, as far as I know.

You might be able to sort of do it, using templates and template metaprogramming, like the Boost library for units of measure that GlenH7 mentioned, but that approach will take a LOT of typing and a lot of pain. You lose ALL of your predefined operations, and have to reimplement the ones you need, in the template metaprogramming syntax.

What you want is something like the Ada type and subtype system. Ada allows you to define new types, derived from an existing type, that might have identical ranges, but are not directly assignable or type-compatible, and new subtypes, that are directly assignable and type-compatible.

  • -1: For this purpose, C++ templates are much more powerful than Ada generics. With automatic instantiation of types and functions, it is possible to get complete compile-time dimensional analysis. Ada generics are not as powerful because all types and free functions must be explicitly instantiated. Compile-time dimensional analysis is not practical in Ada without compiler modifications. See people.cs.kuleuven.be/~dirk.craeynest/ada-belgium/events/13/… – kevin cline Jun 17 '14 at 18:31
  • @kevincline, the explicit instantiation requirement is arguably a Good Thing. As I recall, it was Tony Hoare who proposed a set of default typing rules, analogous to the FORTRAN I-N integer rule, to the ALGOL committee. They chastised him most severely, explaining that requiring explicit declaration of variables, and their types, reduced programming errors. (The author of that tale added that this happened BEFORE anyone knew the possibly-apocryphal story of the lost interplanetary probe, caused by a typo combined with default typing in FORTRAN.) – John R. Strohm Jun 17 '14 at 20:40
  • perhaps, but explicit instantiation prevents a lot of very useful compile-time type calculus. The result is that for many applications (e.g. engineering calculations involving diverse physical units) C++ can provide more compile-time type safety than Ada. There's no analogy between the implicit typing of FORTRAN and the automatic generation of new types for the results of computations. Also FORTRAN had implicit type conversions making the consequences of an unfortunate name choice potentially catastrophic. – kevin cline Jun 17 '14 at 21:16
  • The question is whether you want to catch the error the moment you utter it, or when you try to store it and discover the types don't match up. Over fifty years of computer science seems to suggest that you want to catch the error as early as possible. A complicated expression with two errors, in the presence of implicit type calculus, could wind up generating total garbage with a correct result signature, which is the worst-case scenario. – John R. Strohm Jun 17 '14 at 21:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.