# Unity A Proposal to Add Strong Type Aliases to the Standard Language

This topic is 2001 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey, I want strong type aliases in C++. I've never written a standard proposal before, so here's my attempt.

View PDF online

Any suggestions, additions, rewordings, and etc... you are able to offer would be much appreciated. After the community reviews and improves it, I'll email it to the standards committee (which are currently accepting proposals for C++ TR2), so it can hopefully be read and discussed at a committee meeting for addition to the C++ standard.

I would really appreciate it!

Aside from non-static data member initializers, which was added into C++11 (thank you, whoever submitted that proposal!), strong typedefs are one of my most desired C++ features.

Edited by Servant of the Lord

##### Share on other sites

Hm... Can I ask why this feature is vital? Conversion between

typedef unsigned int Centimeters;
typedef unsigned int Inches;

are legal as for me, as the real types are the same.

For incompatible types gcc (at least) drops an error:

??[santa@yukio ~ $] ? ??> g++ test.cpp -o test -pedantic -Wall test.cpp: In function ‘int main()’: test.cpp:9:8: error: cannot convert ‘MyFloat {aka float}’ to ‘MyInt {aka void*}’ for argument ‘1’ to ‘void test(MyInt)’ ??[santa@yukio ~$]
?
??> cat test.cpp
typedef void* MyInt;
typedef float MyFloat;

void test(MyInt) {
}

int main() {
MyFloat f;
test(f);
return 0;
}

For compatible types you won't get an error even without typedefs:

??[santa@yukio ~ $] ? ??> g++ test.cpp -o test -pedantic -Wall test.cpp: In function ‘int main()’: test.cpp:9:8: warning: ‘f’ is used uninitialized in this function [-Wuninitialized] ??[santa@yukio ~$]
?
??> cat test.cpp
void test(int) {
}

int main() {
float f;
test(f);
return 0;
}

##### Share on other sites
Thanks SiCrane, I assumed there were prior proposals but didn't find them. I'll read over them.
Hm... Can I ask why this feature is vital? Conversion between
typedef unsigned int Centimeters;
typedef unsigned int Inches;
are legal as for me, as the real types are the same.

For incompatible types gcc (at least) drops an error: ...

For compatible types you won't get an error even without typedefs: ...

That's precisely the point. I don't want Centimeters and Inches to be convertible, except explicitly. Strong aliases should refuse to compile aliases made even from the same base type. You need a function to convert from Centimeters to Inches, because 1 Centimeter is not 1 Inch, and doing myCentimeters = myInches is easy to do and almost always a bug. Edited by Servant of the Lord

##### Share on other sites

[quote name='Servant of the Lord' timestamp='1356723633' post='5015148']
I don't want Centimeters and Inches to be convertible
[/quote]

Well and I don't understand why. As I wrote earlier built-in types with similar (in fact equal) semantics _are_ convertible. In your example you are trying to introduce a new type (not an alias in fact, alias is usually just another typename). Simple constructions such as fancy_typedef old_type new_type' aren't able to describe the type semantics at all (both Centimeters and Inches are just lexems for compiler, you don't define what can be done to them). If you suggest semantics should be copied from the old_type than new_type would be just a typename, not a new type.

##### Share on other sites

I don't want Centimeters and Inches to be convertible

Well and I don't understand why. As I wrote earlier built-in types with similar (in fact equal) semantics _are_ convertible.

You seriously don't understand why it's desirable to get a compiler error if someone has a quantity in centimeters and tries to use it where a quantity in inches is expected? I am not sure how else to explain it, since SOTL has been very clear.

##### Share on other sites

[quote name='Álvaro' timestamp='1356725134' post='5015153']
You seriously don't understand why it's desirable to get a compiler error if someone has a quantity in centimeters and tries to use it where a quantity in inches is expected?
[/quote]

This is not my point. My point is thats not a compiler (c++ grammar) problem. Its worth implementing as a part of an STL.

##### Share on other sites

You seriously don't understand why it's desirable to get a compiler error if someone has a quantity in centimeters and tries to use it where a quantity in inches is expected?

This is not my point. My point is thats not a compiler (c++ grammar) problem. Its worth implementing as a part of an STL.

Well, it's a problem where the compiler could help, if it implemented what we are discussing.

I have felt the need for something like this when I have classes Vector3D and Point3D, which are essentially the same thing, but I need to define them separately if I want the type system to help me make sure my operations make sense (e.g., you are not allowed to add points, but adding vectors is fine, and so is adding a point and a vector).

Since we are dealing with units, I just wrote this little test that seems to work fine:
#include <iostream>

namespace units {
template <int m_pow, int kg_pow, int s_pow>
struct unit {
double value;
explicit unit(double value) : value(value) {
}
};

template <int m_pow, int kg_pow, int s_pow>
unit<m_pow,kg_pow,s_pow> operator+(unit<m_pow,kg_pow,s_pow> u1, unit<m_pow,kg_pow,s_pow> u2) {
return unit<m_pow,kg_pow,s_pow>(u1.value+u2.value);
}

unit<0,0,0> operator+(unit<0,0,0> u, double d) {
return unit<0,0,0>(u.value+d);
}

unit<0,0,0> operator+(double d, unit<0,0,0> u) {
return unit<0,0,0>(d+u.value);
}

template <int m_pow, int kg_pow, int s_pow>
unit<m_pow,kg_pow,s_pow> operator-(unit<m_pow,kg_pow,s_pow> u1, unit<m_pow,kg_pow,s_pow> u2) {
return unit<m_pow,kg_pow,s_pow>(u1.value-u2.value);
}

unit<0,0,0> operator-(unit<0,0,0> u, double d) {
return unit<0,0,0>(u.value-d);
}

unit<0,0,0> operator-(double d, unit<0,0,0> u) {
return unit<0,0,0>(d-u.value);
}

template <int m_pow1, int kg_pow1, int s_pow1, int m_pow2, int kg_pow2, int s_pow2>
unit<m_pow1+m_pow2,kg_pow1+kg_pow2,s_pow1+s_pow2> operator*(unit<m_pow1,kg_pow1,s_pow1> u1, unit<m_pow2,kg_pow2,s_pow2> u2) {
return unit<m_pow1+m_pow2,kg_pow1+kg_pow2,s_pow1+s_pow2>(u1.value*u2.value);
}

template <int m_pow, int kg_pow, int s_pow>
unit<m_pow,kg_pow,s_pow> operator*(unit<m_pow,kg_pow,s_pow> u, double d) {
return unit<m_pow,kg_pow,s_pow>(u.value*d);
}

template <int m_pow, int kg_pow, int s_pow>
unit<m_pow,kg_pow,s_pow> operator*(double d, unit<m_pow,kg_pow,s_pow> u) {
return unit<m_pow,kg_pow,s_pow>(d*u.value);
}

template <int m_pow1, int kg_pow1, int s_pow1, int m_pow2, int kg_pow2, int s_pow2>
unit<m_pow1-m_pow2,kg_pow1-kg_pow2,s_pow1-s_pow2> operator/(unit<m_pow1,kg_pow1,s_pow1> u1, unit<m_pow2,kg_pow2,s_pow2> u2) {
return unit<m_pow1-m_pow2,kg_pow1-kg_pow2,s_pow1-s_pow2>(u1.value/u2.value);
}

template <int m_pow, int kg_pow, int s_pow>
unit<m_pow,kg_pow,s_pow> operator/(unit<m_pow,kg_pow,s_pow> u, double d) {
return unit<m_pow,kg_pow,s_pow>(u.value/d);
}

template <int m_pow, int kg_pow, int s_pow>
unit<m_pow,kg_pow,s_pow> operator/(double d, unit<m_pow,kg_pow,s_pow> u) {
return unit<-m_pow,-kg_pow,-s_pow>(d/u.value);
}

template <int m_pow, int kg_pow, int s_pow>
std::ostream &operator<<(std::ostream &os, unit<m_pow,kg_pow,s_pow> u) {
os << u.value;
if (m_pow != 0) {
os << "m";
if (m_pow != 1)
os << "^" << m_pow;
}
if (kg_pow != 0) {
os << "Kg";
if (kg_pow != 1)
os << "^" << kg_pow;
}
if (s_pow != 0) {
os << "s";
if (s_pow != 1)
os << "^" << s_pow;
}
return os;
}

unit<1,0,0> meter(1);
unit<1,0,0> centimeter(0.01);
unit<1,0,0> inch(0.0254);
unit<0,0,1> second(1.0);
unit<0,0,1> minute(60.0);
unit<0,0,1> hour(3600.0);
unit<0,1,0> gram(0.001);
// etc.
}

using namespace units;

int main() {
std::cout << "100 inches/hour = " << (100.0*inch/hour)/(centimeter/minute) << " centimeters/minute\n";
}


Does anyone know if there is a C++ library that does this type of thing? (Oh, and sorry about the hijack...)

##### Share on other sites
boost::units seems to do what you want.

##### Share on other sites

It would be cool if you could define casting operators for opaque typedefs too*:

// Obviously this would require a few changes to the Standard
Inches operator Centimeters() (Centimeters cm)
{
// Estimate
return (cm * 5) / 2;
// Note that the above is merely example code; I realize that a) the above isn't necessarily the
// the right data type, and b) casting it to the right data type could cause recursion without some
// changes or facilities added to the Standard.
}

inline constexpr Centimeters operator"" _cm (int cm)
{
return (Centimeters)cm;
}

Inches i = (Inches)(12_cm); // The point of this code is to show this line`

Also, what would be the implications with promotions? What if you multiplied Inches (which is typedefd as an int) by a float? Or multiplied it by an int?

*This is, I would say, related to opaque typedefs, but is also a bit of a separate issue (because declaring a casting operator makes implicit conversions possible, and AFAIK you can't make a casting operator that requires explicit casting). I suppose you could also say it could work for non-opaque typedefs/implicit conversions, but I don't like the ambiguity of Inches i = 12_cm;

Edited by Cornstalks

1. 1
Rutin
19
2. 2
3. 3
JoeJ
15
4. 4
5. 5

• 22
• 19
• 11
• 13
• 17
• ### Forum Statistics

• Total Topics
631698
• Total Posts
3001768
×