It's possible to use an alias to change the literal signature of a function:
using String = std::string;
void Print(String s) { ... };
But this doesn't disallow calling Print
with a std::string
:
Print(std::string{"Hello world"}); // Still works
This makes sense -- an alias is strictly for simplifying a name for a type, it does not define a new type.
Besides subclassing, which is not a good idea, is there a mechanism by which it's possible to achieve strict typing by name for function parameters? An immediate consequence of this is that this would be possible as well:
using StringA = std::string;
using StringB = std::string;
void Print(StringA s) { ... };
void Print(StringB s) { ... };
Print(StringA{"Hello world"});
Print(StringB{"Hi everyone"});
My current solution is to define simple wrapper classes that hold the type I want to alias as a member. This isn't ideal because it requires duplicating the interface for the member class into the wrapper, something that isn't necessary when using an alias.
The standard makes typedefs and alias a synonym for another type and not a new type:
7.1.3/1: A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration or enum declaration does.
and
7.1.3/2: A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name. It has the same semantics as if it were introduced by the typedef specifier. In particular, it does not define a new type and it shall not appear in the type-id.
So unfortunately, you'll have to continue to use your class wrapper to introduce different types and being able to overload function on this base.