How I format my C++ papers

By Michael Park

Introduction

A few weeks ago, the Fall 2018 C++ Committee meeting took place in San Diego. It was a record-breaking meeting with 274 papers submitted to the pre-meeting mailing and 180 people in attendance. As the number of authors grow, there seems to be an increasing interest in easily creating beautiful documents.

The format of papers vary widely - Plain Text, HTML, LaTeX, Bikeshed, MS Word, etc. Personally, I prefer the look and stability of a PDF document generated from LaTeX. My first paper, N3887 was indeed written in LaTeX: N3887.latex.

But writing LaTeX is a real pain. I couldn’t transfer my thoughts into LaTeX directly so I ended up writing in Google Docs first then converting to LaTeX afterwards. This was completely unreasonable so I started looking for ways to write Markdown instead. I soon came across Pandoc, which is a Swiss army knife that can convert basically any document format to another.

Today, I write my papers in Markdown, which gets translated to LaTeX then generated into a PDF document. Here’s the Tony Table for a snippet of P0655R1:

P0655R1.md P0655R1.pdf

P0655R1-pandoc

P0655R1-pdf

Project Structure

The paper sources live at mpark/wg21, and all of the relevant templates live in the data directory. Given a Pandoc Markdown file <paper>.md at the top-level, make <paper>.pdf generates PDF document via LaTeX at generated/<paper>.pdf and make <paper>.html generates HTML at generated/<paper>.html.

The following sections cover common elements and scenarios in C++ paper writing.

Title

The title is generated by a YAML metadata block.

---
title: "`visit<R>`: Explicit Return Type for `visit`"
document: P0655R1
date: 2018-07-09
audience: Library Evolution Group
author:
  - name: Michael Park
    email: <mcypark@gmail.com>
  - name: Agustín Bergé
    email: <agustinberge@gmail.com>
---

P0655R1-title

Table of Contents

A table of contents is generated by default, but can also be explicitly set via toc: true in the YAML metadata block.

P1260R0.md P1260R0.pdf
---
title: "Pattern Matching"
document: P1260R0
date: 2018-05-22
audience: Evolution
author:
  - name: Michael Park
    email: <mcypark@gmail.com>
toc: true
---

P1260R0-toc

The default depth is 3, but it can be modified with toc-depth: <N>.

---
title: "Pattern Matching"
document: P1260R0
date: 2018-05-22
audience: Evolution
author:
  - name: Michael Park
    email: <mcypark@gmail.com>
toc: true
toc-depth: 4
---

toc-depth-4

It can also be turned off via toc: false.

Markdown

For most of the document content itself, you should simply reach for the basic Markdown functionalities you probably already know, such as headers, lists, quotes, fenced code blocks, inline formatting (bold, italics, strikeout), etc.

You can also refer to the full Pandoc Markdown specification for extensions!

Code Examples

Code examples are written with cpp code blocks as you normally would. The thing to note is that the annotations that appear time to time in “Standardese C++” such as see below, unspecified, and INVOKE are formatted automatically without any decorations in the code.

```cpp
  template <class F, class... BoundArgs>
    unspecified bind(F&&, BoundArgs&&...);
  template <class R, class F, class... BoundArgs>
    unspecified bind(F&&, BoundArgs&&...);
```

P0655R1-code

Of course that means if you name a variable unspecified, it’ll unintentionally be italicized. At least for now… just, don’t do that 😅.

Tony Tables

Tony Tables are before/after tables showing the code we had to write without the proposed feature, and the code we get to write with the proposed feature.

While this post is merely about formatting C++ papers, I will say that if you don’t have Tony Tables in your paper, you’re likely not communicating the value of your feature as effectively as you could be.

Tony Tables are fenced Div blocks that open with ::: tonytable and close with :::. Fenced code blocks are the only elements that actually get added to Tony Tables, except that the last header (if any) before a fenced code block is attached to the cell above.

Here is an example Tony Table:

::: tonytable

### Before
```cpp
switch (x) {
  case 0: std::cout << "got zero"; break;
  case 1: std::cout << "got one"; break;
  default: std::cout << "don't care";
}
```

### After
```cpp
inspect (x) {
  0: std::cout << "got zero";
  1: std::cout << "got one";
  _: std::cout << "don't care";
}
```

:::

tonytable-simple

Each fenced code block element is pushed onto the current row of the table, and horizontal rules (---) are used to move to the next row. You can also control the width of a column by adding a width=<float> attribute to a header.

Here is a more elaborate example:

::: tonytable

### Before {width=.53}
```cpp
std::visit([&](auto&& x) {
  strm << "got auto: " << x;
}, v);
```

### After {width=.47}
```cpp
inspect (v) {
  <auto> x: strm << "got auto: " << x;
}
```

---

```cpp
std::visit([&](auto&& x) {
  using X = std::remove_cvref_t<decltype(x)>;
  if constexpr (C1<X>()) {
    strm << "got C1: " << x;
  } else if constexpr (C2<X>()) {
    strm << "got C2: " << x;
  }
}, v);
```

```cpp
inspect (v) {
  <C1> c1: strm << "got C1: " << c1;
  <C2> c2: strm << "got C2: " << c2;
}
```

:::

tonytable-elaborate

Proposed Wording

This section of the paper is generally where most diffs (code and wording) appear.

Code Changes

Code changes are written with diff code blocks as you normally would.

  • Unchanged: No marker
  • Added: + marker
  • Removed: - marker
```diff
// 20.3.4: tuple-like access to pair:
template <size_t I, class T1, class T2>
-  constexpr typename tuple_element<I, std::pair<T1, T2> >::type&
+  constexpr tuple_element_t<I, pair<T1, T2> >&
-    get(std::pair<T1, T2>&) noexcept;
+    get(pair<T1, T2>&) noexcept;
```

code-diff

Wording Changes

Wording changes are written with fenced Div blocks (similar to Tony Tables) for large changes or bracketed Span for small changes.

Fenced Div blocks open with ::: add or ::: rm and close with ::::

> \pnum{1} Let _n_ be `sizeof...(Variants)`. Let `m` be a pack of _n_ values of type
> `size_t`. Such a pack is called valid if $0 \leq$ `m`_~i~_ <
> `variant_size_v<remove_reference_t<Variants`_~i~_`>>` for all $0 \leq i < n$.
> For each valid pack `m`, let _e_(`m`) denote the expression:
>
> > \small _`INVOKE`_`(std::forward<Visitor>(vis), get<m>(std::forward<Variants>(vars))...)` _// see 19.14.3_
>
> ::: add
> for the first form and
>
> > \small _`INVOKE`_`<R>(std::forward<Visitor>(vis), get<m>(std::forward<Variants>(vars))...)` _// see 19.14.3_
>
> for the second form.
> :::

div-diff

Bracketed Span either looks like [<new text>]{.add} or [<old text>]{.rm}.

> \pnum{3} _Returns:_ _e_(`m`), where `m` is the pack for which `m`_~i~_ is
> `vars`_~i~_`.index()` for all $0 \leq i < n$. The return type is
> `decltype(`_e_(`m`)`)` [for the first form]{.add}.

span-diff

Grammar Changes

Grammar changes are written with line blocks (|) in order to preserve the leading spaces.

> | *selection-statement:*
> |     `if constexpr`*~opt~* `(` *init-statement~opt~* *condition* `)` *statement*
> |     `if constexpr`*~opt~* `(` *init-statement~opt~* *condition* `)` *statement* `else` *statement*
> |     `switch (` *init-statement~opt~* *condition* `)` *statement*
> |     [`inspect constexpr`*~opt~* `(` *init-statement~opt~* *condition* `) {` *inspect-case-seq* `}`]{.add}
>
> ::: add
> | *inspect-case-seq:*
> |     *inspect-case*
> |     *inspect-case-seq* *inspect-case*
>
> | *inspect-case:*
> |     *attribute-specifier-seq~opt~* *inspect-pattern* *inspect-guard~opt~* `:` *statement*
>
> | *inspect-pattern:*
> |     *wildcard-pattern*
> |     *identifier-pattern*
> |     *constant-pattern*
> |     *structured-binding-pattern*
> |     *alternative-pattern*
> |     *binding-pattern*
> |     *extractor-pattern*
>
> | *inspect-guard:*
> |     `if (` *expression* `)`
> :::

grammar-diff

References

Similar to Title, references are generated by a YAML metadata block.

---
references:
  - id: N3546
    citation-label: N3546
    title: "TransformationTraits Redux"
    author:
      family: Brown
      given: [Walter, E.]
    issued:
      year: 2013
    URL: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3546.pdf
  - id: N3655
    citation-label: N3655
    title: "TransformationTraits Redux, v2"
    author:
      family: Brown
      given: [Walter, E.]
    issued:
      year: 2013
    URL: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3655.pdf
  - id: N3797
    citation-label: N3797
    title: "Working Draft, Standard for Programming Language C++"
    author:
      family: Toit
      given: [Stefanus, Du]
    issued:
      year: 2013
    URL: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf
---

references

Citations

In-text citations look like this: [@<citation-label>]

# Introduction

This paper is inspired by [@N3655], section 3 of which was adopted at WG21's
2013 Bristol meeting. That section provided (as did its predecessor [@N3546])
template aliases for the result of _metafunctions_ in `<type_traits>`.
However, the broader question of analogous template aliases throughout
the remainder of the standard library was not addressed.

citation

Final Remarks

In this post, I’ve covered the common elements that I’ve needed writing papers. Writing papers in Markdown has been a sigfinicant improvement for me in smoothly transferring my thoughts onto a paper. Perhaps it’ll be helpful to others as a framework as well 🙂

Also, most of what’s being done here is just Pandoc out of the box. Kudos to the Pandoc developers for an amazing tool!