2

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.

Community
  • 1
  • 1
huu
  • 7,032
  • 2
  • 34
  • 49
  • 1
    Note that the second answer indicates that making a derived class in your situation may be reasonable if you are careful: http://stackoverflow.com/a/6014514/951890 – Vaughn Cato Oct 05 '15 at 04:24
  • That's an excellent analysis. Thanks for pointing that out, I often ignore unselected answers but that was a humbling read. – huu Oct 07 '15 at 17:27

3 Answers3

3

You are taking the right approach. Wrapping an object of the original type is the best that you can currently do.

I recently talked about this topic at CppCon 2015, and have open-sourced a library that makes it convenient to make an "opaque typedef" for integer types: https://sourceforge.net/projects/opaque-typedef/

Be aware that it can be beneficial to customize the interface of your new type, to remove operations that would be errors for your purposes, and to add deliberate interoperability with other types. Slides from my presentation.

PaperBirdMaster
  • 12,806
  • 9
  • 48
  • 94
Kyle Markley
  • 155
  • 4
  • I actually saw your talk (I was one of the lightning talk speakers in your group), and it's what made me question if there was a language mechanism already in place for opaque typedefs. – huu Oct 07 '15 at 17:29
2

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.

Christophe
  • 68,716
  • 7
  • 72
  • 138
2

No, there is no way to get a new type without actually creating a new type (class, struct, enum).

However, there is a brand new proposal to add such a mechanism, perhaps using newtype as a keyword instead of typedef.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203