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:

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

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

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

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&&...); ```

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"; } ``` :::

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; } ``` :::

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

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; ```

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

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

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* `)` > :::

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

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.

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!