使用别名严格输入函数参数

Using aliases for strictly typing function parameters

可以使用别名来更改函数的文字签名:

using String = std::string;

void Print(String s) { ... };

但这并不禁止使用 std::string:

调用 Print
Print(std::string{"Hello world"}); // Still works

这是有道理的 -- 别名只是为了简化类型的名称,而不是定义新类型。

除了 subclassing,即 not a good idea,是否有一种机制可以通过函数参数的名称实现严格类型化?这样做的直接结果是这也是可能的:

using StringA = std::string;
using StringB = std::string;

void Print(StringA s) { ... };
void Print(StringB s) { ... };

Print(StringA{"Hello world"});
Print(StringB{"Hi everyone"});

我目前的解决方案是定义简单的包装器 classes 来保存我想作为成员别名的类型。这并不理想,因为它需要将成员 class 的接口复制到包装器中,这在使用别名时是不必要的。

该标准使 typedef 和别名成为另一种类型的同义词,而不是新类型:

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.

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.

很遗憾,您将不得不继续使用 class 包装器来引入不同的类型并能够在此基础上重载函数。

不,如果不实际创建新类型(class、结构、枚举),就无法获得新类型。

不过,有a brand new proposal加入这样的机制,或许使用newtype作为关键字,而不是typedef

您采取的方法是正确的。包装原始类型的对象是您目前可以做的最好的事情。

我最近在 CppCon 2015 上谈到了这个话题,并开源了一个库,可以方便地为整数类型制作 "opaque typedef": https://sourceforge.net/projects/opaque-typedef/

请注意,自定义新类型的界面、删除对您的目的而言可能出错的操作以及添加与其他类型的有意互操作性可能是有益的。 Slides from my presentation.