Skip to content

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?

Answer
shipping it

Clean compile, no warnings. <% and %> are braces, and and and not are && and !.

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

Open in Compiler Explorer ↗ Quiz this entry