deploy: 94fe31eb9b
This commit is contained in:
1 parent
41c601a7d1
commit
d2e264bd84
1400 files changed
+11859
-5440
No files matched your search
@@ -0,0 +1,366 @@
|
||||
<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=author content="Niels Lohmann"><link href="https://json.nlohmann.me/features/type_recipes/" rel="canonical"><link href=../arbitrary_types/ rel=prev><link href=../binary_formats/ rel=next><link rel=icon href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.7.7"><title>Recipes for Common Types - JSON for Modern C++</title><link rel=stylesheet href=../../assets/stylesheets/main.ec1eaa64.min.css><link rel=stylesheet href=../../assets/stylesheets/palette.ab4e12ef.min.css><link rel="stylesheet" href="../../assets/external/fonts.googleapis.com/css.61a430c9.css"><style>:root{--md-text-font:"Roboto";--md-code-font:"JetBrains Mono"}</style><link rel=stylesheet href=../../css/custom.css><script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script></head> <body dir=ltr data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#recipes-for-common-types class=md-skip> Skip to content </a> </div> <div data-md-component=announce> </div> <header class=md-header data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../.. title="JSON for Modern C++" class="md-header__button md-logo" aria-label="JSON for Modern C++" data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> JSON for Modern C++ </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> Recipes for Common Types </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to dark mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> <input class=md-option data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme=slate data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to light mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script> <label class="md-header__button md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.Line truncated
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><memory></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><vector></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=p>;</span>
|
||||
|
||||
<span class=k>namespace</span><span class=w> </span><span class=nn>nlohmann</span>
|
||||
<span class=p>{</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>T</span><span class=o>></span>
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>adl_serializer</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>shared_ptr</span><span class=o><</span><span class=n>T</span><span class=o>>></span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>to_json</span><span class=p>(</span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>shared_ptr</span><span class=o><</span><span class=n>T</span><span class=o>>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=o>*</span><span class=n>p</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>shared_ptr</span><span class=o><</span><span class=n>T</span><span class=o>>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>is_null</span><span class=p>())</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>make_shared</span><span class=o><</span><span class=n>T</span><span class=o>></span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>std</span><span class=o>::</span><span class=n>remove_const</span><span class=o><</span><span class=n>T</span><span class=o>>::</span><span class=n>type</span><span class=o>></span><span class=p>());</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=k>template</span><span class=w> </span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>T</span><span class=o>></span>
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>adl_serializer</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>T</span><span class=o>>></span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>to_json</span><span class=p>(</span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>T</span><span class=o>>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=o>*</span><span class=n>p</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>T</span><span class=o>>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>is_null</span><span class=p>())</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>make_unique</span><span class=o><</span><span class=n>T</span><span class=o>></span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>T</span><span class=o>></span><span class=p>());</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>};</span>
|
||||
<span class=p>}</span><span class=w> </span><span class=c1>// namespace nlohmann</span>
|
||||
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>point</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=kt>int</span><span class=w> </span><span class=n>x</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=kt>int</span><span class=w> </span><span class=n>y</span><span class=p>;</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=n>NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE</span><span class=p>(</span><span class=n>point</span><span class=p>,</span><span class=w> </span><span class=n>x</span><span class=p>,</span><span class=w> </span><span class=n>y</span><span class=p>)</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=n>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=c1>// an empty pointer is written as null</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>shared_ptr</span><span class=o><</span><span class=n>point</span><span class=o>>></span><span class=w> </span><span class=n>points</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>{</span><span class=n>std</span><span class=o>::</span><span class=n>make_shared</span><span class=o><</span><span class=n>point</span><span class=o>></span><span class=p>(</span><span class=n>point</span><span class=p>{</span><span class=mi>1</span><span class=p>,</span><span class=w> </span><span class=mi>2</span><span class=p>}),</span><span class=w> </span><span class=nb>nullptr</span><span class=p>};</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>points</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=c1>// reading allocates new objects</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>back</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>shared_ptr</span><span class=o><</span><span class=n>point</span><span class=o>>>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>back</span><span class=p>[</span><span class=mi>0</span><span class=p>]</span><span class=o>-></span><span class=n>x</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>", "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>back</span><span class=p>[</span><span class=mi>0</span><span class=p>]</span><span class=o>-></span><span class=n>y</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>", "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=p>(</span><span class=n>back</span><span class=p>[</span><span class=mi>1</span><span class=p>]</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=nb>nullptr</span><span class=p>)</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=c1>// pointers to const and unique_ptr work as well</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>const_ptr</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>[</span><span class=mi>0</span><span class=p>].</span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>shared_ptr</span><span class=o><</span><span class=k>const</span><span class=w> </span><span class=n>point</span><span class=o>>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>unique</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>[</span><span class=mi>0</span><span class=p>].</span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>point</span><span class=o>>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>const_ptr</span><span class=o>-></span><span class=n>y</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>", "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>unique</span><span class=o>-></span><span class=n>x</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
</code></pre></div> <p>Output:</p> <div class=highlight><pre><span></span><code>[{"x":1,"y":2},null]
|
||||
1, 2, 1
|
||||
2, 1
|
||||
</code></pre></div> </details> <p>With this, containers of smart pointers, pointers to <code>const</code>, and members of these types in your own structs convert as usual. A pointer to a base class cannot be filled this way, because <code>T</code> would have to be created as a derived type; see the next section.</p> <p>Reading creates a new object. Two <code>shared_ptr</code>s that pointed to the same object are written twice and read back as two separate objects.</p> <h2 id=class-hierarchies>Class hierarchies<a class=headerlink href=#class-hierarchies title="Permanent link">¶</a></h2> <div class="admonition tip"> <p class=admonition-title>Derived classes whose type is known at compile time</p> <p>If you only need to serialize the data members of a derived class, and the code always knows the concrete type, you do not need a type tag. The <a href=../arbitrary_types/#simplify-your-life-with-macros><code>NLOHMANN_DEFINE_DERIVED_TYPE_*</code> macros</a> (since version 3.12.0) add the members of the derived class to those of its base class. This section is for the case where the concrete type is only known at run time, such as a <code>std::unique_ptr<shape></code> that holds a circle or a rectangle.</p> </div> <p><abbr title="JavaScript Object Notation">JSON</abbr> has no notion of types, so a value in a hierarchy needs a <strong>type tag</strong> that says which derived class to create. Write the tag in the object, and select the class from it when reading:</p> <details class=example> <summary>Example: serialize a class hierarchy with a type tag</summary> <div class=highlight><pre><span></span><code><span class=cp>#include</span><span class=w> </span><span class=cpf><iostream></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><memory></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><stdexcept></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><vector></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=p>;</span>
|
||||
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>shape</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>virtual</span><span class=w> </span><span class=o>~</span><span class=n>shape</span><span class=p>()</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=k>default</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=k>virtual</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=nf>serialize</span><span class=p>()</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>0</span><span class=p>;</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>circle</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>shape</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>radius</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=k>explicit</span><span class=w> </span><span class=n>circle</span><span class=p>(</span><span class=kt>double</span><span class=w> </span><span class=n>r</span><span class=p>)</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>radius</span><span class=p>(</span><span class=n>r</span><span class=p>)</span><span class=w> </span><span class=p>{}</span>
|
||||
|
||||
<span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>serialize</span><span class=p>()</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>override</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=p>{{</span><span class=s>"type"</span><span class=p>,</span><span class=w> </span><span class=s>"circle"</span><span class=p>},</span><span class=w> </span><span class=p>{</span><span class=s>"radius"</span><span class=p>,</span><span class=w> </span><span class=n>radius</span><span class=p>}};</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>rectangle</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>shape</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>width</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>height</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=n>rectangle</span><span class=p>(</span><span class=kt>double</span><span class=w> </span><span class=n>w</span><span class=p>,</span><span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>h</span><span class=p>)</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>width</span><span class=p>(</span><span class=n>w</span><span class=p>),</span><span class=w> </span><span class=n>height</span><span class=p>(</span><span class=n>h</span><span class=p>)</span><span class=w> </span><span class=p>{}</span>
|
||||
|
||||
<span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>serialize</span><span class=p>()</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>override</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=p>{{</span><span class=s>"type"</span><span class=p>,</span><span class=w> </span><span class=s>"rectangle"</span><span class=p>},</span><span class=w> </span><span class=p>{</span><span class=s>"width"</span><span class=p>,</span><span class=w> </span><span class=n>width</span><span class=p>},</span><span class=w> </span><span class=p>{</span><span class=s>"height"</span><span class=p>,</span><span class=w> </span><span class=n>height</span><span class=p>}};</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=k>namespace</span><span class=w> </span><span class=nn>nlohmann</span>
|
||||
<span class=p>{</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><></span>
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>adl_serializer</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>shape</span><span class=o>>></span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>to_json</span><span class=p>(</span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>shape</span><span class=o>>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=n>p</span><span class=o>-></span><span class=n>serialize</span><span class=p>()</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>json</span><span class=p>(</span><span class=nb>nullptr</span><span class=p>);</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>shape</span><span class=o>>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>is_null</span><span class=p>())</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=p>.</span><span class=n>reset</span><span class=p>();</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=o>&</span><span class=w> </span><span class=n>type</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"type"</span><span class=p>).</span><span class=n>get_ref</span><span class=o><</span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>&></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>type</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=s>"circle"</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>make_unique</span><span class=o><</span><span class=n>circle</span><span class=o>></span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"radius"</span><span class=p>).</span><span class=n>get</span><span class=o><</span><span class=kt>double</span><span class=o>></span><span class=p>());</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span><span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>type</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=s>"rectangle"</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>make_unique</span><span class=o><</span><span class=n>rectangle</span><span class=o>></span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"width"</span><span class=p>).</span><span class=n>get</span><span class=o><</span><span class=kt>double</span><span class=o>></span><span class=p>(),</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"height"</span><span class=p>).</span><span class=n>get</span><span class=o><</span><span class=kt>double</span><span class=o>></span><span class=p>());</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>throw</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>invalid_argument</span><span class=p>(</span><span class=s>"unknown shape type: "</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=n>type</span><span class=p>);</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>};</span>
|
||||
<span class=p>}</span><span class=w> </span><span class=c1>// namespace nlohmann</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=n>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>shape</span><span class=o>>></span><span class=w> </span><span class=n>shapes</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>shapes</span><span class=p>.</span><span class=n>push_back</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>make_unique</span><span class=o><</span><span class=n>circle</span><span class=o>></span><span class=p>(</span><span class=mf>1.5</span><span class=p>));</span>
|
||||
<span class=w> </span><span class=n>shapes</span><span class=p>.</span><span class=n>push_back</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>make_unique</span><span class=o><</span><span class=n>rectangle</span><span class=o>></span><span class=p>(</span><span class=mi>2</span><span class=p>,</span><span class=w> </span><span class=mi>3</span><span class=p>));</span>
|
||||
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>shapes</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=c1>// reading creates objects of the derived types</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>back</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>shape</span><span class=o>>>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>boolalpha</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"first is a circle: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=p>(</span><span class=k>dynamic_cast</span><span class=o><</span><span class=n>circle</span><span class=o>*></span><span class=p>(</span><span class=n>back</span><span class=p>[</span><span class=mi>0</span><span class=p>].</span><span class=n>get</span><span class=p>())</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>)</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"second is a rectangle: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=p>(</span><span class=k>dynamic_cast</span><span class=o><</span><span class=n>rectangle</span><span class=o>*></span><span class=p>(</span><span class=n>back</span><span class=p>[</span><span class=mi>1</span><span class=p>].</span><span class=n>get</span><span class=p>())</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>)</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=c1>// an unknown type tag is reported</span>
|
||||
<span class=w> </span><span class=k>try</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>json</span><span class=p>{{</span><span class=s>"type"</span><span class=p>,</span><span class=w> </span><span class=s>"star"</span><span class=p>}}.</span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>shape</span><span class=o>>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>catch</span><span class=w> </span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>invalid_argument</span><span class=o>&</span><span class=w> </span><span class=n>e</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>e</span><span class=p>.</span><span class=n>what</span><span class=p>()</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>}</span>
|
||||
</code></pre></div> <p>Output:</p> <div class=highlight><pre><span></span><code>[{"radius":1.5,"type":"circle"},{"height":3.0,"type":"rectangle","width":2.0}]
|
||||
first is a circle: true
|
||||
second is a rectangle: true
|
||||
unknown shape type: star
|
||||
</code></pre></div> </details> <p>A <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>unique_ptr</span><span class=o><</span><span class=n>shape</span><span class=o>>></span></code> converts to an array of tagged objects and back, creating a <code>circle</code> and a <code>rectangle</code>. The same works for <code>std::shared_ptr<shape></code>. Remember the virtual destructor: without it, deleting a derived object through the base pointer is undefined behavior.</p> <h2 id=stdvariant><code>std::variant</code><a class=headerlink href=#stdvariant title="Permanent link">¶</a></h2> <p>A variant has the same problem: the alternative must be recorded. If the alternatives are your own types, write a type tag next to their members, exactly as for a hierarchy:</p> <details class=example> <summary>Example: serialize a std::variant with a type tag</summary> <div class=highlight><pre><span></span><code><span class=cp>#include</span><span class=w> </span><span class=cpf><iostream></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><stdexcept></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><variant></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><vector></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=p>;</span>
|
||||
|
||||
<span class=k>namespace</span><span class=w> </span><span class=nn>geo</span>
|
||||
<span class=p>{</span>
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>circ</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>radius</span><span class=p>;</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>rect</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>width</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>height</span><span class=p>;</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=n>NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE</span><span class=p>(</span><span class=n>circ</span><span class=p>,</span><span class=w> </span><span class=n>radius</span><span class=p>)</span>
|
||||
<span class=n>NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE</span><span class=p>(</span><span class=n>rect</span><span class=p>,</span><span class=w> </span><span class=n>width</span><span class=p>,</span><span class=w> </span><span class=n>height</span><span class=p>)</span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>figure</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>variant</span><span class=o><</span><span class=n>circ</span><span class=p>,</span><span class=w> </span><span class=n>rect</span><span class=o>></span><span class=p>;</span>
|
||||
|
||||
<span class=kt>void</span><span class=w> </span><span class=nf>to_json</span><span class=p>(</span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>figure</span><span class=o>&</span><span class=w> </span><span class=n>f</span><span class=p>)</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>visit</span><span class=p>([</span><span class=o>&</span><span class=n>j</span><span class=p>](</span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=o>&</span><span class=w> </span><span class=n>alternative</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>alternative</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>},</span><span class=w> </span><span class=n>f</span><span class=p>);</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=p>[</span><span class=s>"type"</span><span class=p>]</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>holds_alternative</span><span class=o><</span><span class=n>circ</span><span class=o>></span><span class=p>(</span><span class=n>f</span><span class=p>)</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=s>"circ"</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=s>"rect"</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
|
||||
<span class=kt>void</span><span class=w> </span><span class=nf>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>figure</span><span class=o>&</span><span class=w> </span><span class=n>f</span><span class=p>)</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=o>&</span><span class=w> </span><span class=n>type</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"type"</span><span class=p>).</span><span class=n>get_ref</span><span class=o><</span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>&></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>type</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=s>"circ"</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>f</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>circ</span><span class=o>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span><span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>type</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=s>"rect"</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>f</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>rect</span><span class=o>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>else</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>throw</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>invalid_argument</span><span class=p>(</span><span class=s>"unknown figure type: "</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=n>type</span><span class=p>);</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>}</span>
|
||||
<span class=p>}</span><span class=w> </span><span class=c1>// namespace geo</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=n>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>geo</span><span class=o>::</span><span class=n>figure</span><span class=o>></span><span class=w> </span><span class=n>figures</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>{</span><span class=n>geo</span><span class=o>::</span><span class=n>circ</span><span class=p>{</span><span class=mi>2</span><span class=p>},</span><span class=w> </span><span class=n>geo</span><span class=o>::</span><span class=n>rect</span><span class=p>{</span><span class=mi>3</span><span class=p>,</span><span class=w> </span><span class=mi>4</span><span class=p>}};</span>
|
||||
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>figures</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>back</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>geo</span><span class=o>::</span><span class=n>figure</span><span class=o>>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"alternatives read back: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>back</span><span class=p>[</span><span class=mi>0</span><span class=p>].</span><span class=n>index</span><span class=p>()</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>", "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>back</span><span class=p>[</span><span class=mi>1</span><span class=p>].</span><span class=n>index</span><span class=p>()</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
</code></pre></div> <p>Output:</p> <div class=highlight><pre><span></span><code>[{"radius":2.0,"type":"circ"},{"height":4.0,"type":"rect","width":3.0}]
|
||||
alternatives read back: 0, 1
|
||||
</code></pre></div> </details> <p>In the example, the functions are found because <code>geo</code> is the namespace of the template arguments of <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>variant</span><span class=o><</span><span class=n>circ</span><span class=p>,</span><span class=w> </span><span class=n>rect</span><span class=o>></span></code>; for a variant of only standard types (for example <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>variant</span><span class=o><</span><span class=kt>int</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>></span></code>) there is no such namespace, and you need an <code>adl_serializer</code> specialization or a wrapper type of your own.</p> <p>If the alternatives are <abbr title="JavaScript Object Notation">JSON</abbr>-native (numbers, strings, ...), a variant such as <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>variant</span><span class=o><</span><span class=kt>int</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>></span></code> can instead be written as the plain value, and read by testing the <abbr title="JavaScript Object Notation">JSON</abbr> type (<code>is_number_integer()</code>, <code>is_string()</code>) to choose the alternative.</p> <h2 id=stdchrono><code>std::chrono</code><a class=headerlink href=#stdchrono title="Permanent link">¶</a></h2> <p>A duration is written as an object with the keys <code>unit</code> and <code>value</code>, for example <code>{"unit": "ms", "value": 1500}</code>, so the <abbr title="JavaScript Object Notation">JSON</abbr> value is self-describing. The serializer names the unit of the period (<code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>min</code>, <code>h</code>; extend the list for other periods), and the deserializer rejects a value whose unit differs from the requested duration type instead of silently misreading it:</p> <details class=example> <summary>Example: serialize durations and system_clock time points</summary> <div class=highlight><pre><span></span><code><span class=cp>#include</span><span class=w> </span><span class=cpf><chrono></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><iostream></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><stdexcept></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><string></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=p>;</span>
|
||||
|
||||
<span class=c1>// the name of a period; extend the list for the periods you use</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>Period</span><span class=o>></span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>unit_name</span><span class=p>();</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><></span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>nano</span><span class=o>></span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=s>"ns"</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><></span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>micro</span><span class=o>></span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=s>"us"</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><></span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>milli</span><span class=o>></span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=s>"ms"</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><></span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>ratio</span><span class=o><</span><span class=mi>1</span><span class=o>>></span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=s>"s"</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><></span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>ratio</span><span class=o><</span><span class=mi>60</span><span class=o>>></span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=s>"min"</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><></span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>ratio</span><span class=o><</span><span class=mi>3600</span><span class=o>>></span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=s>"h"</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
|
||||
<span class=k>namespace</span><span class=w> </span><span class=nn>nlohmann</span>
|
||||
<span class=p>{</span>
|
||||
<span class=k>template</span><span class=w> </span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>Rep</span><span class=p>,</span><span class=w> </span><span class=k>typename</span><span class=w> </span><span class=nc>Period</span><span class=o>></span>
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>adl_serializer</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>duration</span><span class=o><</span><span class=n>Rep</span><span class=p>,</span><span class=w> </span><span class=n>Period</span><span class=o>>></span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>to_json</span><span class=p>(</span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>duration</span><span class=o><</span><span class=n>Rep</span><span class=p>,</span><span class=w> </span><span class=n>Period</span><span class=o>>&</span><span class=w> </span><span class=n>d</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>{{</span><span class=s>"unit"</span><span class=p>,</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>Period</span><span class=o>></span><span class=p>()},</span><span class=w> </span><span class=p>{</span><span class=s>"value"</span><span class=p>,</span><span class=w> </span><span class=n>d</span><span class=p>.</span><span class=n>count</span><span class=p>()}};</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>duration</span><span class=o><</span><span class=n>Rep</span><span class=p>,</span><span class=w> </span><span class=n>Period</span><span class=o>>&</span><span class=w> </span><span class=n>d</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"unit"</span><span class=p>).</span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>></span><span class=p>()</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=n>unit_name</span><span class=o><</span><span class=n>Period</span><span class=o>></span><span class=p>())</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=k>throw</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>invalid_argument</span><span class=p>(</span><span class=s>"unexpected unit "</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"unit"</span><span class=p>).</span><span class=n>dump</span><span class=p>());</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=n>d</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>duration</span><span class=o><</span><span class=n>Rep</span><span class=p>,</span><span class=w> </span><span class=n>Period</span><span class=o>></span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"value"</span><span class=p>).</span><span class=n>get</span><span class=o><</span><span class=n>Rep</span><span class=o>></span><span class=p>());</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>};</span>
|
||||
|
||||
<span class=k>template</span><span class=w> </span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>Duration</span><span class=o>></span>
|
||||
<span class=k>struct</span><span class=w> </span><span class=nc>adl_serializer</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>time_point</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>system_clock</span><span class=p>,</span><span class=w> </span><span class=n>Duration</span><span class=o>>></span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>to_json</span><span class=p>(</span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>time_point</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>system_clock</span><span class=p>,</span><span class=w> </span><span class=n>Duration</span><span class=o>>&</span><span class=w> </span><span class=n>t</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>t</span><span class=p>.</span><span class=n>time_since_epoch</span><span class=p>();</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
|
||||
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>time_point</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>system_clock</span><span class=p>,</span><span class=w> </span><span class=n>Duration</span><span class=o>>&</span><span class=w> </span><span class=n>t</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>t</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>time_point</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>chrono</span><span class=o>::</span><span class=n>system_clock</span><span class=p>,</span><span class=w> </span><span class=n>Duration</span><span class=o>></span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>Duration</span><span class=o>></span><span class=p>());</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>};</span>
|
||||
<span class=p>}</span><span class=w> </span><span class=c1>// namespace nlohmann</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=n>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=k>using</span><span class=w> </span><span class=k>namespace</span><span class=w> </span><span class=nn>std</span><span class=o>::</span><span class=nn>chrono</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>boolalpha</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=c1>// the unit is part of the JSON value</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>timeout</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>milliseconds</span><span class=p>(</span><span class=mi>1500</span><span class=p>);</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"duration: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>timeout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"as milliseconds: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>timeout</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>milliseconds</span><span class=o>></span><span class=p>().</span><span class=n>count</span><span class=p>()</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=c1>// reading with a different unit is rejected</span>
|
||||
<span class=w> </span><span class=k>try</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>timeout</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>seconds</span><span class=o>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=w> </span><span class=k>catch</span><span class=w> </span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>invalid_argument</span><span class=o>&</span><span class=w> </span><span class=n>e</span><span class=p>)</span>
|
||||
<span class=w> </span><span class=p>{</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"error: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>e</span><span class=p>.</span><span class=n>what</span><span class=p>()</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
|
||||
<span class=w> </span><span class=c1>// a system_clock time point is the time since the Unix epoch</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>time_point</span><span class=o><</span><span class=n>system_clock</span><span class=p>,</span><span class=w> </span><span class=n>milliseconds</span><span class=o>></span><span class=w> </span><span class=n>t</span><span class=p>(</span><span class=n>milliseconds</span><span class=p>(</span><span class=mi>1700000000123</span><span class=p>));</span>
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>stamp</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>t</span><span class=p>;</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"time point: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=n>stamp</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
|
||||
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>back</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>stamp</span><span class=p>.</span><span class=n>get</span><span class=o><</span><span class=n>time_point</span><span class=o><</span><span class=n>system_clock</span><span class=p>,</span><span class=w> </span><span class=n>milliseconds</span><span class=o>>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=s>"round trip: "</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=p>(</span><span class=n>back</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=n>t</span><span class=p>)</span><span class=w> </span><span class=o><<</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
|
||||
<span class=p>}</span>
|
||||
</code></pre></div> <p>Output:</p> <div class=highlight><pre><span></span><code>duration: {"unit":"ms","value":1500}
|
||||
as milliseconds: 1500
|
||||
error: unexpected unit "ms"
|
||||
time point: {"unit":"ms","value":1700000000123}
|
||||
round trip: true
|
||||
</code></pre></div> </details> <p>A <code>system_clock::time_point</code> with millisecond precision is written as the duration since the Unix epoch, that is, as an object with <code>unit</code> and <code>value</code>. The time point serializer is limited to <code>system_clock</code>, because the epoch of other clocks (for example <code>steady_clock</code>) has no meaning outside the running program.</p> <p>If you prefer a text representation such as <abbr title="International Organization for Standardization">ISO</abbr> 8601 (<code>2023-11-14T22:13:20Z</code>), write the string with <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>format</span><span class=p>(</span><span class=s>"{:%FT%TZ}"</span><span class=p>,</span><span class=w> </span><span class=n>t</span><span class=p>)</span></code> and read it with <code>std::chrono::parse</code> (both C++20), or with a date library, in the same two functions.</p> <h2 id=see-also>See also<a class=headerlink href=#see-also title="Permanent link">¶</a></h2> <ul> <li><a href=../arbitrary_types/ >Arbitrary type conversions</a> - the conversion mechanism and macros</li> <li><a href=../arbitrary_types/#why-isnt-my-to_json-or-from_json-found>Why isn't my <code>to_json</code> found?</a></li> <li><a href=../conversions/ >Converting values</a> - <code>get</code>, implicit conversions, and <code>std::optional</code></li> </ul> <!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary --> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date" title="October 25, 2026 11:07:32 UTC">October 25, 2026</span> </span> </aside> </article> </div> <script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> <div class=md-copyright__highlight> Copyright © 2013-2026 Niels Lohmann </div> </div> <div class=md-social> <a href="https://github.com/nlohmann" target="_blank" rel="noopener" title="github.com" class="md-social__link"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </a> <a href="https://www.linkedin.com/in/nielslohmann/" target="_blank" rel="noopener" title="www.linkedinLine truncated
|
||||
@@ -0,0 +1,450 @@
|
||||
# Recipes for Common Types
|
||||
|
||||
The library converts the standard containers, strings, numbers, tuples, `std::optional`, and `std::filesystem::path` (the last two since version 3.12.0, C++17) out of the box, and your own types once you write conversion functions or use the macros (see [Arbitrary type conversions](https://json.nlohmann.me/features/arbitrary_types/index.md)). It deliberately does **not** convert smart pointers, `std::variant`, `std::chrono` types, or class hierarchies, because there is more than one reasonable JSON representation for each of them. This page shows a representation for each that you can copy and adapt.
|
||||
|
||||
All recipes use a specialization of [`adl_serializer`](https://json.nlohmann.me/api/adl_serializer/index.md), which you may provide for types you do not own, or free `to_json`/`from_json` functions in the namespace of the type. Place them where they are visible before any code that converts the type; see [Why isn't my `to_json` found?](https://json.nlohmann.me/features/arbitrary_types/#why-isnt-my-to_json-or-from_json-found).
|
||||
|
||||
## Smart pointers
|
||||
|
||||
A `std::shared_ptr<T>` or `std::unique_ptr<T>` is written as the value it points to, or as `null` for an empty pointer, and read back by allocating a new `T`:
|
||||
|
||||
Example: serialize shared_ptr and unique_ptr
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
template <typename T>
|
||||
struct adl_serializer<std::shared_ptr<T>>
|
||||
{
|
||||
static void to_json(json& j, const std::shared_ptr<T>& p)
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
j = *p;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::shared_ptr<T>& p)
|
||||
{
|
||||
if (j.is_null())
|
||||
{
|
||||
p = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = std::make_shared<T>(j.get<typename std::remove_const<T>::type>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct adl_serializer<std::unique_ptr<T>>
|
||||
{
|
||||
static void to_json(json& j, const std::unique_ptr<T>& p)
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
j = *p;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::unique_ptr<T>& p)
|
||||
{
|
||||
if (j.is_null())
|
||||
{
|
||||
p = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = std::make_unique<T>(j.get<T>());
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
||||
struct point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(point, x, y)
|
||||
|
||||
int main()
|
||||
{
|
||||
// an empty pointer is written as null
|
||||
const std::vector<std::shared_ptr<point>> points = {std::make_shared<point>(point{1, 2}), nullptr};
|
||||
const json j = points;
|
||||
std::cout << j << '\n';
|
||||
|
||||
// reading allocates new objects
|
||||
const auto back = j.get<std::vector<std::shared_ptr<point>>>();
|
||||
std::cout << back[0]->x << ", " << back[0]->y << ", " << (back[1] == nullptr) << '\n';
|
||||
|
||||
// pointers to const and unique_ptr work as well
|
||||
const auto const_ptr = j[0].get<std::shared_ptr<const point>>();
|
||||
const auto unique = j[0].get<std::unique_ptr<point>>();
|
||||
std::cout << const_ptr->y << ", " << unique->x << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
[{"x":1,"y":2},null]
|
||||
1, 2, 1
|
||||
2, 1
|
||||
```
|
||||
|
||||
With this, containers of smart pointers, pointers to `const`, and members of these types in your own structs convert as usual. A pointer to a base class cannot be filled this way, because `T` would have to be created as a derived type; see the next section.
|
||||
|
||||
Reading creates a new object. Two `shared_ptr`s that pointed to the same object are written twice and read back as two separate objects.
|
||||
|
||||
## Class hierarchies
|
||||
|
||||
Derived classes whose type is known at compile time
|
||||
|
||||
If you only need to serialize the data members of a derived class, and the code always knows the concrete type, you do not need a type tag. The [`NLOHMANN_DEFINE_DERIVED_TYPE_*` macros](https://json.nlohmann.me/features/arbitrary_types/#simplify-your-life-with-macros) (since version 3.12.0) add the members of the derived class to those of its base class. This section is for the case where the concrete type is only known at run time, such as a `std::unique_ptr<shape>` that holds a circle or a rectangle.
|
||||
|
||||
JSON has no notion of types, so a value in a hierarchy needs a **type tag** that says which derived class to create. Write the tag in the object, and select the class from it when reading:
|
||||
|
||||
Example: serialize a class hierarchy with a type tag
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct shape
|
||||
{
|
||||
virtual ~shape() = default;
|
||||
virtual json serialize() const = 0;
|
||||
};
|
||||
|
||||
struct circle : shape
|
||||
{
|
||||
double radius;
|
||||
|
||||
explicit circle(double r) : radius(r) {}
|
||||
|
||||
json serialize() const override
|
||||
{
|
||||
return {{"type", "circle"}, {"radius", radius}};
|
||||
}
|
||||
};
|
||||
|
||||
struct rectangle : shape
|
||||
{
|
||||
double width;
|
||||
double height;
|
||||
|
||||
rectangle(double w, double h) : width(w), height(h) {}
|
||||
|
||||
json serialize() const override
|
||||
{
|
||||
return {{"type", "rectangle"}, {"width", width}, {"height", height}};
|
||||
}
|
||||
};
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
template <>
|
||||
struct adl_serializer<std::unique_ptr<shape>>
|
||||
{
|
||||
static void to_json(json& j, const std::unique_ptr<shape>& p)
|
||||
{
|
||||
j = p ? p->serialize() : json(nullptr);
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::unique_ptr<shape>& p)
|
||||
{
|
||||
if (j.is_null())
|
||||
{
|
||||
p.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& type = j.at("type").get_ref<const std::string&>();
|
||||
if (type == "circle")
|
||||
{
|
||||
p = std::make_unique<circle>(j.at("radius").get<double>());
|
||||
}
|
||||
else if (type == "rectangle")
|
||||
{
|
||||
p = std::make_unique<rectangle>(j.at("width").get<double>(), j.at("height").get<double>());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument("unknown shape type: " + type);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
||||
int main()
|
||||
{
|
||||
std::vector<std::unique_ptr<shape>> shapes;
|
||||
shapes.push_back(std::make_unique<circle>(1.5));
|
||||
shapes.push_back(std::make_unique<rectangle>(2, 3));
|
||||
|
||||
const json j = shapes;
|
||||
std::cout << j << '\n';
|
||||
|
||||
// reading creates objects of the derived types
|
||||
const auto back = j.get<std::vector<std::unique_ptr<shape>>>();
|
||||
std::cout << std::boolalpha;
|
||||
std::cout << "first is a circle: " << (dynamic_cast<circle*>(back[0].get()) != nullptr) << '\n';
|
||||
std::cout << "second is a rectangle: " << (dynamic_cast<rectangle*>(back[1].get()) != nullptr) << '\n';
|
||||
|
||||
// an unknown type tag is reported
|
||||
try
|
||||
{
|
||||
json{{"type", "star"}}.get<std::unique_ptr<shape>>();
|
||||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
[{"radius":1.5,"type":"circle"},{"height":3.0,"type":"rectangle","width":2.0}]
|
||||
first is a circle: true
|
||||
second is a rectangle: true
|
||||
unknown shape type: star
|
||||
```
|
||||
|
||||
A `std::vector<std::unique_ptr<shape>>` converts to an array of tagged objects and back, creating a `circle` and a `rectangle`. The same works for `std::shared_ptr<shape>`. Remember the virtual destructor: without it, deleting a derived object through the base pointer is undefined behavior.
|
||||
|
||||
## `std::variant`
|
||||
|
||||
A variant has the same problem: the alternative must be recorded. If the alternatives are your own types, write a type tag next to their members, exactly as for a hierarchy:
|
||||
|
||||
Example: serialize a std::variant with a type tag
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace geo
|
||||
{
|
||||
struct circ
|
||||
{
|
||||
double radius;
|
||||
};
|
||||
|
||||
struct rect
|
||||
{
|
||||
double width;
|
||||
double height;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(circ, radius)
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(rect, width, height)
|
||||
|
||||
using figure = std::variant<circ, rect>;
|
||||
|
||||
void to_json(json& j, const figure& f)
|
||||
{
|
||||
std::visit([&j](const auto & alternative)
|
||||
{
|
||||
j = alternative;
|
||||
}, f);
|
||||
j["type"] = std::holds_alternative<circ>(f) ? "circ" : "rect";
|
||||
}
|
||||
|
||||
void from_json(const json& j, figure& f)
|
||||
{
|
||||
const auto& type = j.at("type").get_ref<const std::string&>();
|
||||
if (type == "circ")
|
||||
{
|
||||
f = j.get<circ>();
|
||||
}
|
||||
else if (type == "rect")
|
||||
{
|
||||
f = j.get<rect>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument("unknown figure type: " + type);
|
||||
}
|
||||
}
|
||||
} // namespace geo
|
||||
|
||||
int main()
|
||||
{
|
||||
const std::vector<geo::figure> figures = {geo::circ{2}, geo::rect{3, 4}};
|
||||
|
||||
const json j = figures;
|
||||
std::cout << j << '\n';
|
||||
|
||||
const auto back = j.get<std::vector<geo::figure>>();
|
||||
std::cout << "alternatives read back: " << back[0].index() << ", " << back[1].index() << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
[{"radius":2.0,"type":"circ"},{"height":4.0,"type":"rect","width":3.0}]
|
||||
alternatives read back: 0, 1
|
||||
```
|
||||
|
||||
In the example, the functions are found because `geo` is the namespace of the template arguments of `std::variant<circ, rect>`; for a variant of only standard types (for example `std::variant<int, std::string>`) there is no such namespace, and you need an `adl_serializer` specialization or a wrapper type of your own.
|
||||
|
||||
If the alternatives are JSON-native (numbers, strings, ...), a variant such as `std::variant<int, std::string>` can instead be written as the plain value, and read by testing the JSON type (`is_number_integer()`, `is_string()`) to choose the alternative.
|
||||
|
||||
## `std::chrono`
|
||||
|
||||
A duration is written as an object with the keys `unit` and `value`, for example `{"unit": "ms", "value": 1500}`, so the JSON value is self-describing. The serializer names the unit of the period (`ns`, `us`, `ms`, `s`, `min`, `h`; extend the list for other periods), and the deserializer rejects a value whose unit differs from the requested duration type instead of silently misreading it:
|
||||
|
||||
Example: serialize durations and system_clock time points
|
||||
|
||||
```
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// the name of a period; extend the list for the periods you use
|
||||
template <typename Period> const char* unit_name();
|
||||
template <> const char* unit_name<std::nano>()
|
||||
{
|
||||
return "ns";
|
||||
}
|
||||
template <> const char* unit_name<std::micro>()
|
||||
{
|
||||
return "us";
|
||||
}
|
||||
template <> const char* unit_name<std::milli>()
|
||||
{
|
||||
return "ms";
|
||||
}
|
||||
template <> const char* unit_name<std::ratio<1>>()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
template <> const char* unit_name<std::ratio<60>>()
|
||||
{
|
||||
return "min";
|
||||
}
|
||||
template <> const char* unit_name<std::ratio<3600>>()
|
||||
{
|
||||
return "h";
|
||||
}
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
template <typename Rep, typename Period>
|
||||
struct adl_serializer<std::chrono::duration<Rep, Period>>
|
||||
{
|
||||
static void to_json(json& j, const std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
j = {{"unit", unit_name<Period>()}, {"value", d.count()}};
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
if (j.at("unit").get<std::string>() != unit_name<Period>())
|
||||
{
|
||||
throw std::invalid_argument("unexpected unit " + j.at("unit").dump());
|
||||
}
|
||||
d = std::chrono::duration<Rep, Period>(j.at("value").get<Rep>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Duration>
|
||||
struct adl_serializer<std::chrono::time_point<std::chrono::system_clock, Duration>>
|
||||
{
|
||||
static void to_json(json& j, const std::chrono::time_point<std::chrono::system_clock, Duration>& t)
|
||||
{
|
||||
j = t.time_since_epoch();
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::chrono::time_point<std::chrono::system_clock, Duration>& t)
|
||||
{
|
||||
t = std::chrono::time_point<std::chrono::system_clock, Duration>(j.get<Duration>());
|
||||
}
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
std::cout << std::boolalpha;
|
||||
|
||||
// the unit is part of the JSON value
|
||||
const json timeout = milliseconds(1500);
|
||||
std::cout << "duration: " << timeout << '\n';
|
||||
std::cout << "as milliseconds: " << timeout.get<milliseconds>().count() << '\n';
|
||||
|
||||
// reading with a different unit is rejected
|
||||
try
|
||||
{
|
||||
timeout.get<seconds>();
|
||||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
std::cout << "error: " << e.what() << '\n';
|
||||
}
|
||||
|
||||
// a system_clock time point is the time since the Unix epoch
|
||||
const time_point<system_clock, milliseconds> t(milliseconds(1700000000123));
|
||||
const json stamp = t;
|
||||
std::cout << "time point: " << stamp << '\n';
|
||||
|
||||
const auto back = stamp.get<time_point<system_clock, milliseconds>>();
|
||||
std::cout << "round trip: " << (back == t) << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
duration: {"unit":"ms","value":1500}
|
||||
as milliseconds: 1500
|
||||
error: unexpected unit "ms"
|
||||
time point: {"unit":"ms","value":1700000000123}
|
||||
round trip: true
|
||||
```
|
||||
|
||||
A `system_clock::time_point` with millisecond precision is written as the duration since the Unix epoch, that is, as an object with `unit` and `value`. The time point serializer is limited to `system_clock`, because the epoch of other clocks (for example `steady_clock`) has no meaning outside the running program.
|
||||
|
||||
If you prefer a text representation such as ISO 8601 (`2023-11-14T22:13:20Z`), write the string with `std::format("{:%FT%TZ}", t)` and read it with `std::chrono::parse` (both C++20), or with a date library, in the same two functions.
|
||||
|
||||
## See also
|
||||
|
||||
- [Arbitrary type conversions](https://json.nlohmann.me/features/arbitrary_types/index.md) - the conversion mechanism and macros
|
||||
- [Why isn't my `to_json` found?](https://json.nlohmann.me/features/arbitrary_types/#why-isnt-my-to_json-or-from_json-found)
|
||||
- [Converting values](https://json.nlohmann.me/features/conversions/index.md) - `get`, implicit conversions, and `std::optional`
|
||||
Reference in new issue
Block a user