Why do C++ templates use the angle bracket syntax?
Asked Answered
M

1

44

The titular question refers to the design decisions in the C++ standard that introduced templates around 1990.

Why did the designers use <> (angle brackets) instead of, say, () (round brackets)? Doing so would have saved lots of programmers from the bit-shift related error

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

that got only fixed in C++11. I do not see the rationale of introducing additional syntax like that when, arguably, round brackets would have served the same purpose while keeping the changes minimalist. Insted you could have used

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

Can somebody well-versed in the history of C++ dig out the original design rationale for using angle brackets? Alternatively, can you show why other solutions would not have worked as well?

Mouldy answered 6/4, 2017 at 11:34 Comment(17)
Because function pointers. int(int(int)) obj; would make obj a pointer to a function which returns int and takes a pointer to a function which returns int and takes int. Or something like that.Tableau
@DeiDei Technically that syntax would be int obj(int(int)).Feathering
Round brackets are even more problematic with function templates: in template_function(int())(), is int() a template argument or a function argument?Velar
I don't see how auto template parameter deduction could work. With round brackets you have ambiguity... are those arguments for the template or for the template instantiation ?Coenzyme
You all miss the point of the question: why angle bracket and not other tokens?Fuselage
@ysc Assuming unicode, there are billions of alternative characters. Should we cover them one by one? Must in each case there be a proof it is worse than <>? That almost certainly is not the process that was used to decide on <>: describing the entire process is too broad for SO. Anything else is an opinion, simplification, or lie. The short answer is "that is what was standardized, which is why we use it". I doubt that would satisfy. Does the OP want minutes? Recollections of people on the committee at the time?Way
@Yakk I didn't say it's not what's to be answered. I'm just saying nitpicking about parenthesis is not helping ;).Fuselage
@Yakk - Unicode was not an option since C++ was designed when people were primarily using ASCII for programming. Thus it was only parenthesis or {} or [] that had alternative matching symbols, and they were all at least as problematic.Endoplasm
@Yakk: some documents that reflect the design process would be nice. There certainly was not only one person involved in crafting the template system in the C++ language.Mouldy
@cpplearner: The type deduction for templated functions is a good point.Mouldy
Personally I think both template parameters <> and normal function parameters () should be changed to use curly braces {}. Then C++ be like: {class A}class B{B{}{}}; B{int} b{}; So much easier...Divulsion
Because C++ isn't LISP. <g>Salba
Fun fact: Anything matching (roughly) the regex <.*?> in plaintext is automatically stripped, unless it's one of a few allowed HTML tags. In this case, <angle brackets> met those critera, so it was removed from the rendered output. I've fixed the issue in this one, but it's worth keeping in mind in the future. Also, if you don't like my fix, please feel free to change it, but keep in mind the requirements for them to be visible.Reface
@Hans Olsson: Re "..designed when people were primarily using ASCII for programming...". Oh, you mean today :-)Alpha
Worth pointing out that D uses TemplatedType!(T), which doesn't have the ambiguity problem because there's not binary ! in C++.Grose
there are a lot of unused symbols on the keyboard like `, #, @. I don't know why they're not consideredMannie
@Feathering more precisely it would be: int (*obj)(int (*foo) (int i) --- :D this would make obj a pointer to a function which returns int and takes a pointer to a function named foo which returns int and takes an int named i -- is c++ doing all this syntax implicitly?Flavius
F
97

Templates were introduced in the 1988 USENIX paper Parameterized Types for C++ by Bjarne Stroustrup, later incorporated into The Annotated C++ Reference Manual published in 1990 (the version before standardized C++). According to the paper,

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)

The paper also explained why the template and class keywords are used.

Note that the Stroustrup placed the <…> after the variable name in the same manner as int x[10] to argue against (…), though this placement is never used elsewhere in the paper.

His argument that "using (…) can lead to obscure/ambiguous code" is still valid though. As mentioned in this question's comment, using parenthesis T(x) leads to ambiguity with function type or function call (note that T can be a function template and C++ allowed values to be template arguments).

Similarly, using square brackets T[x] leads to ambiguity with array type or indexing.

I don't see why T{x} cannot be used yet, maybe it was simply not considered, or maybe it is too ugly to have {…} used everywhere.

Feathering answered 6/4, 2017 at 12:41 Comment(4)
"I don't see why T{x} cannot be used yet" Well now it's used for new-style construction so wouldn't work for templates anyway. ideone.com/0cADl9Horwitz
@Horwitz yes it certainly is ambiguous in 2011 but I don't see the reason to reject it in 1988. Unless the new-style construction syntax was actually planned 30 years ago ^_^.Feathering
Well, {} already had two uses back then (for blocks and old-style initializers), so while there would probably not be any syntactic ambiguity, it would be even more confusing for the programmer.Tabathatabb
Thank you for digging out this paper, including the practical demonstration.Mouldy

© 2022 - 2024 — McMap. All rights reserved.