为什么C++模板使用尖括号语法?

44

这个标题提到的问题涉及到C++标准在1990年左右引入模板时的设计决策。

为什么设计者使用尖括号<>而不是圆括号()?这样做可以避免许多程序员因位移相关错误而烦恼。

std::vector<std::vector<int>> // does not work until C++11

这个问题只在C++11中得到了修复。我不明白为什么要引入额外的语法,当使用圆括号可能会达到同样的效果,同时保持变化的最小化。相反,您可以使用

标签。

template(typename T) // Define template if round brackets could be used
mytemplate { ... }
...
...
mytemplate(mytemplate(int)) obj; //Instantiate template when round brackets could be used

有没有精通 C++ 历史的人可以挖掘一下使用尖括号的最初设计理念?或者,您能否说明为什么其他解决方案同样适用不了呢?


31
因为函数指针。int(int(int)) obj; 会使obj成为一个指向返回 int 并且接受一个指向返回 int 并且接受 int 的函数指针。或者类似于这样的东西。 - DeiDei
11
圆括号在函数模板中更加棘手:在template_function(int())()中,int()是模板参数还是函数参数? - cpplearner
5
假设使用Unicode编码,存在数十亿个备选字符。我们是否需要一一覆盖它们?每种情况下是否都必须有证据证明它比“<>”更糟糕?几乎可以肯定,并不是采用这种过程来决定使用“<>”,描述整个过程对于SO来说太广泛了。其他任何答案都是意见、简化或谎言。简短的答案是:“这就是被标准化的原因,这就是我们使用它的原因。”我怀疑这并不能令人满意。提问者是否想要会议记录?委员会成员当时的回忆? - Yakk - Adam Nevraumont
7
因为在C++设计时人们主要使用ASCII进行编程,所以Unicode不是一个选择。因此,只有圆括号、大括号或中括号具有替代匹配符号,它们都存在至少同样的问题。 - Hans Olsson
3
值得指出的是,D语言使用TemplatedType!(T),它没有二进制的,因此不存在C++中存在的歧义问题。 - Cubic
显示剩余12条评论
1个回答

97

模板最初是由Bjarne Stroustrup在1988年的USENIX论文《C++参数化类型》中引入的,后来被纳入1990年出版的《C++注释参考手册》(标准化之前的版本)。根据这篇论文所述,

The <…> brackets are used in preference to the parentheses (…) partly to emphasize the different nature of template arguments (they will be evaluated at compile time) and partly because parentheses are already hopelessly overused in C++.

9.2. <…> vs (…)

But why use brackets instead of parentheses? As mentioned before, parentheses already have many uses in C++. A syntactic clue (the <…> brackets) can be usedful for reminding the user about the different nature of the type parameters (they are evaluated at compile time). Furthermore, the use of parentheses could lead to pretty obscure code:

template(int sz = 20) class buffer {
    buffer(int i = 10);
    // ...
};
buffer b1(100)(200);
buffer b2(100);      // b2(100)(10) or b2(20)(100)?
buffer b3;           // legal?

These problems would become a serious practical concern if the notation for explicit disambiguation of overloaded function calls were adopted. The chosen alternative seems much cleaner:

template<int sz = 20> class buffer {
    buffer(sz)(int i = 10);
    // ...
};
buffer b1<100>(200);
buffer b2<100>;      // b2<100>(10)
buffer b3;           // b3<20>(10)
buffer b4(100);      // b4<20>(100)
本文还解释了为什么使用templateclass关键字。请注意,Stroustrup以与int x[10]相同的方式在变量名之后放置了<…>,以反对(…),尽管在本文中没有其他地方使用这种放置方式。然而,他认为“使用(…)可能会导致模糊/歧义的代码”的论点仍然有效。如本问题的评论所述,使用括号T(x)会导致函数类型或函数调用的歧义(请注意,T可以是函数模板,并且C++允许值作为模板参数)。类似地,使用方括号T[x]会导致数组类型或索引的歧义。我不知道为什么T{x}还不能使用,也许它只是被忽略了,或者它太丑了,不能在所有地方使用{…}

1
我不明白为什么T{x}不能使用。现在它被用于新样式的构造,所以无论如何都不能用于模板。http://ideone.com/0cADl9 - JAB
13
@JAB,2011年的确存在歧义,但我不认为拒绝1988年的语法是有道理的,除非新风格的构造语法实际上是30年前就计划好的。^_^ - kennytm
5
那时,“{}”已经有两个用途(表示代码块和旧式初始化器),因此尽管可能不会产生语法歧义,但这会更加令程序员感到困惑。 - Jan Hudec
1
感谢您挖掘出这篇论文,包括其中的实际演示。 - shuhalo

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