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 |
---|---|
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 |
---|---|
|
The default depth is 3
, but it can be modified with toc-depth: <N>
.
|
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 - 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!