Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generic type alias, which are incompatible to each other

I am trying to construct some kind of "generic type alias", meaning I want to define a type as int for example, but with a generic type argument which then makes it incompatible with instances of other types.

I tried doing this with alias templates:

template <typename T>
using NumberWithSemantics = int;

But the problem with this is that all instantiations, no matter the type T, are considered equal, for example:

struct A {};
struct B {};

NumberWithSemantics<A> getThing() {
    return 14;
}

int processDifferentThing(NumberWithSemantics<B> b) {
    return b * 3;
}

int main() {
    auto a = getThing();
    return processDifferentThing(a); // unfortunately compiles just fine
}

Is there a way to define some kind of generic type alias that disallows mixing different template instantiations?

like image 667
Felk Avatar asked Jun 05 '18 21:06

Felk


1 Answers

C++ has type aliasing, but it is only weak type aliasing. When you say

typedef int MyType;

or

using MyType = int;

you tell the compiler, “whenever you see MyType, pretend you had just seen int instead”. There is then no difference at all between MyType i and int i; both create a variable named i of type int. Making the using declaration a template doesn’t help; all of the types equivalently mean int.

What you want to do is create an actual new type. To do this, you need to declare it with struct or class, not just using. Even if they look the same, the type system will treat each new type created this way as a separate type; by extension, if you make a template struct, each instantiation will be a new type.

Therefore, the minimum potential solution would be:

template <typename T>
struct NumberWithSemantics { int i; };

Then you can use NumberWithSemantics<A> and NumberWithSemantics<B> as different types. However, you will need to keep saying .i to get the actual value out, which can make your code harder to read. There are various possible ways to get around that, for which I recommend reading this part of the Strong Types series on Fluent C++.

like image 179
Daniel H Avatar answered Oct 23 '22 03:10

Daniel H