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

Using aliases for strictly typing function parameters

本文关键字:函数 参数 别名      更新时间:2023-10-16

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

using String = std::string;
void Print(String s) { ... };

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

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

这是有意义的——别名严格地用于简化类型的名称,它不定义新类型。

除了子类化,这不是一个好主意,有没有一种机制,通过它可以实现严格的按名称键入函数参数?这样做的直接后果是,这也是可能的:

using StringA = std::string;
using StringB = std::string;
void Print(StringA s) { ... };
void Print(StringB s) { ... };
Print(StringA{"Hello world"});
Print(StringB{"Hi everyone"});

我目前的解决方案是定义简单的包装器类,其中包含我想要作为成员别名的类型。这并不理想,因为它需要将成员类的接口复制到包装器中,而使用别名时则不需要这样做。

你的做法是正确的。包装原始类型的对象是目前你能做的最好的事情。

我最近在CppCon 2015上谈到了这个话题,并且开源了一个库,可以方便地为整数类型创建一个"不透明的类型定义":https://sourceforge.net/projects/opaque-typedef/

请注意,自定义新类型的接口、删除对您的目的来说可能是错误的操作以及有意添加与其他类型的互操作性可能是有益的。我的演讲幻灯片

标准使typedefs和alias成为另一种类型的同义词,而不是新类型:

7.1.3/1:用typedef说明符声明的名称变成typedef-name。在其声明的范围内,typedefine -name为语法上等同于关键字,并命名相关联的类型用第8条中描述的方式进行标识。类型名因此是另一类型的同义词。typedefine -name不引入一个新的类型,就像类声明或enum声明所做的那样。

7.1.3/2: typedefine -name也可以通过别名声明引入。using关键字后面的标识符变成类型名。它具有相同的语义,就好像它是由类型定义说明符。特别是,它没有定义新的类型和它不能出现在类型id中。

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

不,如果不实际创建新类型(class, struct, enum),就无法获得新类型。

然而,有一个全新的建议来添加这样的机制,可能使用newtype作为关键字而不是typedef