Search code examples
c++c++11language-designtemplate-meta-programming

Why do C++ templates use the angle bracket syntax?


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?


Solution

  • 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.