Trivia impact: rare
The Braces That Are Not Braces
valid C++17, with no brace and no && in sight
int main() <%
bool ready = true;
bool busy = false;
if (ready and not busy) <%
std::cout << "shipping it\n";
%>
%>
Does this compile? What does it print?
Why¶
C++ carries a second spelling for tokens that were hard to type on 1980s keyboards
missing {, }, [, ] and #. [lex.digraph] lists the digraphs — <% %> for
braces, <: :> for brackets, %: for # — and the alternative tokens and, or,
not, xor, compl, bitand, bitor, not_eq. These are not macros in C++ but real
keywords, which is why <iso646.h> is empty here and defines them in C. Digraphs are
alternative preprocessing tokens: parsing gives them the same meaning as their primary
forms, although macro stringization can still preserve the spelling (<% rather than
{).
Where it shows up¶
The digraphs are dead, but they left a scar: before C++11, std::vector<::std::string>
tokenized <: as [ and failed to compile, so people wrote a defensive space after the
<. C++11 added a rule to treat < as its own token in exactly that position, and the
spelling works today. The word forms are alive by choice — some codebases prefer
if (ready and not busy) for readability, and it is a normal style opinion rather than a
trick.
Takeaway: and and <% are not macros or extensions — they are C++, spelled the
long way round.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo