为什么C++中的类型别名使用'using'而不是'typedef'?

39

明显的,类型别名和模板类型别名在语义上等同于typedef,并且是支持模板的typedef扩展。为什么针对这些扩展需要创建带有using关键字的新语法,而不是使用typedef进行第一步并使用带有 typedef 词的某些语法扩展。

注意:这不是“使用和typedef之间的区别”问题的克隆。我知道using的优点在于定义一族typedef。我问的是标准人员为什么决定使用using关键字来进行此扩展,而不是typedef关键字。这似乎只会增加语言中的混淆。


3
@Cyber,不是这样。我知道“using”关键字可以定义一组typedef的优点。我的问题是标准委员会为什么决定使用“using”关键字来扩展而不是使用“typedef”关键字。这似乎只会增加语言中的混淆。 - tohava
1
可能与N1406中提到的问题有关,以及N1499如何解决这些问题有关。解决方案体现在语法上:模板别名不会像typedef模板建议的那样定义类型,而是与允许特化的typedef模板的原始提案相反(其中一个版本)。 - dyp
TL;DR 因为 typedef 是一种可怕的难以阅读的 hack,而且有机会用更清晰、更温和的语法来取代它。 - n. m.
dyp typedef并不会添加新的类型,传统上它被称为弱类型,但这只是意味着编译器的类型表中没有新类型。 - phorgan1
2个回答

44
这里是Bjarne Stroustrup关于为什么引入using而不是扩展typedef的说法:
引入关键字using是为了获得一个线性符号“名称后跟其所指代的内容”。我们曾试过传统且复杂的typedef解决方案,但直到我们采用了一种不那么晦涩的语法,才成功地获得了一个完整而连贯的解决方案。
他还声称他更喜欢这种语法来定义常规的typedef

In addition to being important in connection with templates, type aliases can also be used as a different (and IMO better) syntax for ordinary type aliases:

using PF = void (*)(double);

他说得很正确,这看起来非常简洁。相比之下,typedef将会非常复杂,因为名称可能会出现在中间:

typedef void(*PF)(double);

这里有一个来自他们提案的解释(见第4页),更加深入:

It has been suggested to (re)use the keyword typedef — as done in the paper [4] — to introduce template aliases:

template<class T>
typedef std::vector<T,MyAllocator<T>> Vec;

That notation has the advantage of using a keyword already known to introduce a type alias. However, it also displays several disadvantages among which the confusion of using a keyword known to introduce an alias for a type-name in a context where the alias does not designate a type, but a template; Vec is not an alias for a type, and should not be taken for a typedef-name. The name Vec is a name for the family std::vector<*,MyAllocator<*>> - where the asterisk is a placeholder for a type-name. Consequently, we do not propose the "typedef" syntax.

template<class T>
using Vec = std::vector<T,MyAllocator<T>>;

can be read/interpreted as: from now on, I'll be using Vec<T> as a synonym for std::vector<T,MyAllocator<T>>. With that reading, the new syntax for aliasing seems reasonably logical.

所以他基本上有两个观点:

  1. using 模板成为一组类型,而不是一个类型,因此 typedef 是“错误”的
  2. using 几乎可以被读作英语句子

3
我同意他关于最后一点的观点......我会说 using 应该替代 typedef。语法更清晰明了。 - ApproachingDarknessFish
只是为了比较,你可能应该展示一下你的 void(*)(double) 示例的 typedef 是什么样子的。 :) - jalf
关于第一点,同样也可以说类或结构体,而不仅仅是typedef。 - memeplex
1
一直想知道为什么他们从未允许简单地拥有 typedef void(*)(double) PF;。这几乎和 using 一样清晰。模板 typedefs - 好吧,你可以使用它,就像函数指针 typedefs 一样...回到函数指针,实际上,在定义变量时我感觉很像:为什么不是 int(*)(double) callback;?我知道,哲学最终与 char *a, b, *c; 相同。这是我能够阅读的东西,但我从未与之交朋友,并且永远不会在我的代码中使用它,因为我的个人阅读方式不同... - Aconcagua

30
您所建议的实际上是Herb Sutter在2002年提出的文档N1406中提出的。例如,它将允许编写以下代码:
template<typename T> typedef X<T,int> Xi; 

这在N1449中由Gabriel Dos Reis和Mat Marcus进行了修订。他们采用了using语法,并指出以下内容:

请注意,我们特别避免使用“typedef template”一词,并引入了涉及“using”和“=”的新语法以帮助避免混淆:我们在此处不定义任何类型,我们正在引入一个类型的同义词(即别名),该类型是涉及模板参数的类型标识符(即类型表达式)的抽象。

他们还说:

有关语法进行了两次草案投票。绝大多数人投票支持避免使用typedef模板语法,而支持“=”语法。第二次投票表明,与“alias”或本提案草案中缺少任何关键字相比,“using”关键字更受欢迎。使用任何关键字的动机部分源于希望使用可能与上面简要概述的非模板别名方向兼容的语法。

这种语法随后被 Gabriel Dos Reis 和 Bjarne Stroustrup 采纳,并在最终提案 N2258 中使用。

2
您还可以提到关于别名模板语义的讨论,N1406/2.2“主要选择:专业化 vs. 其他一切”。 using = 在语法层面上反映了其语义。 - dyp
一个模板一个参数化类型。 Stroustroup本人甚至在1989年的一篇论文中也这样说[https://www.usenix.org/legacy/publications/compsystems/1989/win_stroustrup.pdf]。所以,我认为它*是*创建了一个新的类型或类型族。但是,我实际上很喜欢新的语法,所以我对C++过于复杂并没有抱怨得多。 - jtchitty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接