<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<title>Inline Variables for the Standard Library</title>

<style type="text/css">
  p {text-align:justify}
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  blockquote.note
  {
   background-color:#E0E0E0;
   padding-left: 15px;
   padding-right: 15px;
   padding-top: 1px;
   padding-bottom: 1px;
  }
</style>
</head><body>
<address style="text-align: left;">
Document number: P0607R0<br/>
Date: 2017-02-27<br/>
Project: Programming Language C++<br/>
Audience: Library Working Group, Library Evolution Working Group<br/>
Authors: Daniel Kr&uuml;gler<br/>
Reply-to: <a href="mailto:daniel.kruegler@gmail.com">Daniel Kr&uuml;gler</a>
</address>
<hr>
<h1 style="text-align: center;">Inline Variables for the Standard Library</h1>

<ul>
<li><a href="#Discussion">Discussion</a></li>
<li><a href="#Rationale">Rationale</a></li>
<li><a href="#Issues_Resolved">Resolved Issues</a></li>
<li><a href="#Proposed_resolution">Proposed Resolution</a></li>
<li><a href="#Akn">Acknowledgements</a></li>
</ul>

<h2><a name="Discussion"></a>Discussion</h2>
<p>
This proposal attempts to provide combined wording for the changes requested by the NB comments
FI 9 and GB 28 against C++17.
<p/>
The general approach is to follow the suggested directions described by the issues:
</p>
<ol>
<li><p><b>Required change:</b> Use <tt>inline</tt> variables for <em>exactly</em> the constants that are listed by at least one
of the two NB comments, which are the following ones:</p>
<ul>
<li><p><tt>piecewise_construct</tt></p></li>
<li><p><tt>allocator_arg</tt></p></li>
<li><p><tt>nullopt</tt></p></li>
<li><p>[<tt>in_place</tt>, <tt>in_place_type</tt>, <tt>in_place_index</tt>]: Already part of the working paper.</p></li>
<li><p><tt>defer_lock</tt></p></li>
<li><p><tt>try_to_lock</tt></p></li>
<li><p><tt>adopt_lock</tt></p></li>
<li><p><tt>bind</tt> placeholders <tt>_1, _2, ...</tt></p></li>
<li><p><tt>ignore</tt></p></li>
<li><p><tt>seq</tt></p></li>
<li><p><tt>par</tt></p></li>
<li><p><tt>par_unseq</tt></p></li>
</ul>
</li>
<li><p><b>Optional change:</b> In addition to the changes above introduce <em>consequenty</em> <tt>inline</tt>
variables <em>for all</em> namespace-scope variables with internal linkage. <b>The proper wording for this
optional change depends on the resolution of core issue 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1713">CWG 1713</a>, therefore the proposed
wording has an additional sub division!</b></p></li>
</ol>

<p>
The changes in regard to consequently introducing <tt>inline</tt> variables have been made optional, because 
this step increases the necessary draft changes significantly and that change was not <em>explicitly</em>
requested by the NB comments. 
</p>

<h2><a name="Rationale"></a>Rationale</h2>
<p>
The author of this paper recommends to apply both <em>two</em> suggested changes (A) and (B1) inspired by the NB 
comments as specified below for the following reasons: Inline variables solve a long-standing problem caused by 
the ODR restrictions of C++. These ODR violations are typically introduced by a basically non-preventable situation 
where a variable with internal linkage is odr-used in a function with external linkage due to this special constraint 
imposed (in more precise words as summarized) by 3.2 [basic.def.odr] (6.2.1.3):
</p>
<blockquote>
<p>
-6- There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.6), inline variable with external linkage (7.1.6), class template (Clause 14), non-static
function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class
template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7,
14.5.5) in a program provided that each definition appears in a different translation unit, and provided
the definitions satisfy the following requirements. Given such an entity named <tt>D</tt> defined in more than one
translation unit, then
</p>
<ol style="list-style-type: none">
<li><p>(6.1) &mdash; [&hellip;]</p></li>
<li><p>(6.2) &mdash; in each definition of <tt>D</tt>, corresponding names, looked up according to 3.4, shall refer to an entity defined
within the definition of <tt>D</tt>, or shall refer to the same entity, after overload resolution (13.3) and after
matching of partial template specialization (14.8.3), except that a name can refer to</p>
<ol style="list-style-type: none">
<li><p>(6.2.1) &mdash; a non-volatile <tt>const</tt> object with internal or no linkage if the object</p>
<ol style="list-style-type: none">
<li><p>(6.2.1.1) &mdash; [&hellip;]</p></li>
<li><p>(6.2.1.2) &mdash; [&hellip;]</p></li>
<li><p>(6.2.1.3) &mdash; is not odr-used in any definition of <tt>D</tt>, and</p></li>
<li><p>(6.2.1.4) &mdash; [&hellip;]</p></li>
</ol>
</li>
<li><p>(6.2.2) &mdash; a reference with internal or no linkage initialized with a constant expression such that the reference
refers to the same entity in all definitions of <tt>D</tt>;</p></li>
</ol>
</li>
<li><p>(6.3) &mdash; [&hellip;]</p></li>
</ol>
</blockquote>
<p>
It should be pointed out, that similar changes to constant <tt>static</tt> data members are not needed, because they have
external linkage and <tt>constexpr</tt> static data members are already implicitly <tt>inline</tt> variables 
(7.1.5 [dcl.constexpr] p1).
<p/>
Another important point to mention is, that as of the current working draft, variable template constants also have
internal linkage and are therefore susceptible to the ODR violation problem unless declared as <tt>inline</tt> variables,
as specified in 3.5 [basic.link] p3:
</p>
<blockquote>
<p>
-3- A name having namespace scope (3.3.6) has internal linkage if it is the name of
</p>
<ol style="list-style-type: none">
<li><p>(3.1) &mdash; [&hellip;]</p></li>
<li><p>(3.2) &mdash; a non-inline variable of non-volatile const-qualified type
that is neither explicitly declared <tt>extern</tt> nor previously declared to
have external linkage; [..]</p></li>
</ol>
</blockquote>
<p>
It is expected that this state will change when <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1713">CWG 1713</a>
will be resolved.
</p>

<h2><a name="Issues_Resolved"></a>Resolved Issues</h2>
<p>
If the proposed resolution would be accepted, the following library issues will be resolved:
</p>
<table border="1">
  <tr>
    <th>Number</th>
    <th>Description</th>
  </tr>
  <tr>
    <td><a href="http://cplusplus.github.io/LWG/lwg-active.html#2888">2888</a></td>
    <td>Variables of library tag types need to be <tt>inline</tt> variables</td>
  </tr>
  <tr>
    <td><a href="http://cplusplus.github.io/LWG/lwg-active.html#2889">2889</a></td>
    <td>Mark <tt>constexpr</tt> global variables as <tt>inline</tt></td>
  </tr>
</table> 

<h2><a name="Proposed_resolution"></a>Proposed Resolution</h2>

<p>
At some places below, additional markup of the form
</p>
<blockquote class="note">
<p>
[<i>Drafting notes</i>: whatever &mdash; <i>end drafting notes</i>]
</p>
</blockquote>
<p>
is provided, which is <em>not</em> part of the normative wording, but is solely shown to provide additional information 
to the reader about the rationale of the concrete wording.
</p>

<blockquote class="note" style="border-style:solid">
<span style="color:#C80000;font-weight:bold">
<p>
The below list of suggested changes is split into two halves: List (A) is an enumeration of suggested <em>minimalistic</em> 
wording changes and only shows changes to types <em>explicitly</em> listed in either of the NB comments, while list (B1) 
and list (B2) separately list the <em>additional</em> necessary changes when a full introduction of <tt>inline</tt> 
variables are considered, depending on the outcome of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1713">CWG 1713</a>. 
<p/>
(B1) and (B2) are mutually exclusive and only <em>one</em> of them can be combined with list (A)!
</p>
</span>
</blockquote>

<p>
The proposed wording changes refer to the Standard C++ working draft 
<a href="http://wg21.link/n4640">N4640</a>.
</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: Searching for current usages of global constant variables in the Library, the following locations are
<em>unaffected</em></tt>:
</p>
<ol>
<li><p>18.6.1 [new.syn]: <tt>nothrow</tt> [Constant with external linkage]</p></li>
<li><p>20.2.1 [utility.syn] <i>"in-place construction"</i>: <tt>in_place</tt>, <tt>in_place_type</tt>, <tt>in_place_index</tt> 
[Already part of the working paper]</p></li>
</ol>
<p>
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<ol style="list-style-type:none">
<li><p>A. <em>Minimalistic</em> suggestion (only the union of those requested by the NB comments):</p>

<ol>
<li><p>Change 20.2.1 [utility.syn], header <tt>&lt;utility&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<ins>inline</ins> constexpr piecewise_construct_t piecewise_construct{};
</pre></blockquote>
</li>

<li><p>Change 20.4.5 [pair.piecewise] before p1 as indicated:</p>

<blockquote><pre>
struct piecewise_construct_t {
  explicit piecewise_construct_t() = default;
};
<ins>inline</ins> constexpr piecewise_construct_t piecewise_construct{};
</pre></blockquote>
</li>

<li><p>Change 20.5.2 [tuple.syn], header <tt>&lt;tuple&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<i>// 20.5.3.4, tuple creation functions</i>
<ins>inline</ins> constexpr <i>unspecified</i> ignore;
</pre></blockquote>
</li>

<li><p>Change 20.6.2 [optional.syn], header <tt>&lt;optional&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<i>// 20.6.4, no-value state indicator</i>
struct nullopt_t{<i>see below</i>};
<ins>inline</ins> constexpr nullopt_t nullopt(<i>unspecified</i>);
</pre></blockquote>
</li>

<li><p>Change 20.6.4 [optional.nullopt] as indicated:</p>

<blockquote><pre>
struct nullopt_t{<i>see below</i>};
<ins>inline</ins> constexpr nullopt_t nullopt(<i>unspecified</i>);
</pre></blockquote>
</li>

<li><p>Change 20.10.2 [memory.syn], header <tt>&lt;memory&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<i>// 20.10.6, allocator argument tag</i>
struct allocator_arg_t { explicit allocator_arg_t() = default; };
<ins>inline</ins> constexpr allocator_arg_t allocator_arg{};
</pre></blockquote>
</li>

<li><p>Change 20.10.6 [allocator.tag] as indicated:</p>

<blockquote><pre>
namespace std {
  struct allocator_arg_t { explicit allocator_arg_t() = default; };
  <ins>inline</ins> constexpr allocator_arg_t allocator_arg{};
}
</pre></blockquote>
</li>

<li><p>Change 20.14.11.4 [func.bind.place] as indicated:</p>

<blockquote>
<p>
-2- Placeholders should be defined as:
</p>
<pre>
<ins>inline</ins> constexpr <i>unspecified</i> _1{};
</pre>
<p>
If they are not, they shall be declared as:
</p>
<pre>
extern <i>unspecified</i> _1;
</pre>
</blockquote>
</li>

<li><p>Change 20.19.2 [execution.syn], header <tt>&lt;execution&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<i>// 20.19.7, execution policy objects</i>
<ins>inline</ins> constexpr sequenced_policy seq{ <i>unspecified</i> };
<ins>inline</ins> constexpr parallel_policy par{ <i>unspecified</i> };
<ins>inline</ins> constexpr parallel_unsequenced_policy par_unseq{ <i>unspecified</i> };
</pre></blockquote>
</li>

<li><p>Change 20.19.7 [execpol.objects] as indicated:</p>

<blockquote><pre>
<ins>inline</ins> constexpr execution::sequenced_policy execution::seq{ <i>unspecified</i> };
<ins>inline</ins> constexpr execution::parallel_policy execution::par{ <i>unspecified</i> };
<ins>inline</ins> constexpr execution::parallel_unsequenced_policy execution::par_unseq{ <i>unspecified</i> };
</pre></blockquote>
</li>

<li><p>Change 30.4.1 [mutex.syn], header <tt>&lt;mutex&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<ins>inline</ins> constexpr defer_lock_t defer_lock { };
<ins>inline</ins> constexpr try_to_lock_t try_to_lock { };
<ins>inline</ins> constexpr adopt_lock_t adopt_lock { };
</pre></blockquote>
</li>

<li><p>Change 30.4.4 [thread.lock] p2 as indicated:</p>

<blockquote><pre>
<ins>inline</ins> constexpr defer_lock_t defer_lock { };
<ins>inline</ins> constexpr try_to_lock_t try_to_lock { };
<ins>inline</ins> constexpr adopt_lock_t adopt_lock { };
</pre></blockquote>
</li>

</ol>

<li><p>B1. <em>Additional</em> suggestion (all remaining cases <em>excluding variable templates</em> where <tt>inline</tt> variables 
would be appropriate, assumes that <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1713">CWG 1713</a> has been
resolved):</p>

<ol>
<li><p>Change 17.4.2.1.3 [enumerated.types] as indicated:</p>

<blockquote>
<p>
-2- The enumerated type <tt><i>enumerated</i></tt> can be written:
</p>
<blockquote><pre>
enum <i>enumerated</i> { <i>V0</i>, <i>V1</i>, <i>V2</i>, <i>V3</i>, ..... };

<ins>inline</ins> <del>static</del> const enumerated <i>C0</i> (<i>V0</i>);
<ins>inline</ins> <del>static</del> const enumerated <i>C1</i> (<i>V1</i>);
<ins>inline</ins> <del>static</del> const enumerated <i>C2</i> (<i>V2</i>);
<ins>inline</ins> <del>static</del> const enumerated <i>C3</i> (<i>V3</i>);
.....
</pre></blockquote>
</li>

<li><p>Change 17.4.2.1.4 [bitmask.types] as indicated:</p>

<blockquote>
<p>
-2- The bitmask type <tt><i>bitmask</i></tt> can be written:
</p>
<blockquote><pre>
[&hellip;]
<ins>inline</ins> constexpr bitmask C0(V0);
<ins>inline</ins> constexpr bitmask C1(V1);
<ins>inline</ins> constexpr bitmask C2(V2);
<ins>inline</ins> constexpr bitmask C3(V3);
</pre></blockquote>
</li>

<li><p>Change 18.6.1 [new.syn], header <tt>&lt;new&gt;</tt> synopsis, as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: The <em>removal</em> of the explicit <tt>static</tt> specifier for the namespace-scope
constants <tt>hardware_destructive_interference_size</tt> and <tt>hardware_constructive_interference_size</tt>  
is still <em>required</em> because adding <tt>inline</tt> alone would still not solve the ODR violation problem here.
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<blockquote><pre>
[&hellip;]
<i>// 18.6.5, hardware interference size</i>
<ins>inline</ins> <del>static</del> constexpr size_t hardware_destructive_interference_size = <i>implementation-defined</i>;
<ins>inline</ins> <del>static</del> constexpr size_t hardware_constructive_interference_size = <i>implementation-defined</i>;
</pre></blockquote>
</li>

<li><p>Change 18.6.5 [hardware.interference] as indicated:</p>

<blockquote><pre>
<ins>inline</ins> constexpr size_t hardware_destructive_interference_size = <i>implementation-defined</i>;
</pre>
<blockquote>
<p>
-1- [&hellip;]
</p>
</blockquote>
<pre>
<ins>inline</ins> constexpr size_t hardware_constructive_interference_size = <i>implementation-defined</i>;
</pre>
<blockquote>
<p>
-2- [&hellip;]
</p>
</blockquote>
</li>

<li><p>Change 20.2.1 [utility.syn], header <tt>&lt;utility&gt;</tt> synopsis, as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: With the acceptance of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1713">CWG 1713</a>
the <tt>inline</tt> specifier is no longer required for const-qualified variable templates, therefore it is recommended to
remove them from the two variable templates <tt>in_place_type</tt> and <tt>in_place_index</tt> (but not from the non-template
constant <tt>in_place</tt>!) &mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<blockquote><pre>
template &lt;class T&gt; <del>inline</del> constexpr in_place_type_t&lt;T&gt; in_place_type{};
[&hellip;]
template &lt;size_t I&gt; <del>inline</del> constexpr in_place_index_t&lt;I&gt; in_place_index{};
</pre></blockquote>
</li>

<li><p>Change 20.7.2 [variant.syn], header <tt>&lt;variant&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<ins>inline</ins> constexpr size_t variant_npos = -1;
</pre></blockquote>
</li>

<li><p>Change 28.5.1 [re.synopt], bitmask type <tt>syntax_option_type</tt> synopsis, as indicated:</p>

<blockquote><pre>
namespace std::regex_constants {
  using syntax_option_type = <i>T1</i>;
  <ins>inline</ins> constexpr syntax_option_type icase = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type nosubs = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type optimize = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type collate = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type ECMAScript = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type basic = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type extended = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type awk = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type grep = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type egrep = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type multiline = <i>unspecified</i>;
}
</pre></blockquote>
</li>

<li><p>Change 28.5.2 [re.matchflag], bitmask type <tt>match_flag_type</tt> synopsis, as indicated:</p>

<blockquote><pre>
namespace std::regex_constants {
  using match_flag_type = <i>T2</i>;
  <ins>inline</ins> constexpr match_flag_type match_default = {};
  <ins>inline</ins> constexpr match_flag_type match_not_bol = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_eol = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_bow = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_eow = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_any = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_null = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_continuous = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_prev_avail = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type format_default = {};
  <ins>inline</ins> constexpr match_flag_type format_sed = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type format_no_copy = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type format_first_only = <i>unspecified</i>;
}
</pre></blockquote>
</li>

<li><p>Change 28.5.3 [re.err], <tt>error_type</tt> synopsis, as indicated:</p>

<blockquote><pre>
namespace std::regex_constants {
  using error_type = <i>T3</i>;
  <ins>inline</ins> constexpr error_type error_collate = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_ctype = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_escape = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_backref = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_brack = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_paren = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_brace = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_badbrace = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_range = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_space = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_badrepeat = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_complexity = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_stack = <i>unspecified</i>;
}
</pre></blockquote>
</li>

</ol>

</li>

<li><p>B2. <em>Additional</em> suggestion (all remaining cases <em>including variable templates</em> where <tt>inline</tt> variables 
would be appropriate, assumes that <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1713">CWG 1713</a> has 
<em>not</em> been resolved):</p>

<ol>
<li><p>Change 17.4.2.1.3 [enumerated.types] as indicated:</p>

<blockquote>
<p>
-2- The enumerated type <tt><i>enumerated</i></tt> can be written:
</p>
<blockquote><pre>
enum <i>enumerated</i> { <i>V0</i>, <i>V1</i>, <i>V2</i>, <i>V3</i>, ..... };

<ins>inline</ins> <del>static</del> const enumerated <i>C0</i> (<i>V0</i>);
<ins>inline</ins> <del>static</del> const enumerated <i>C1</i> (<i>V1</i>);
<ins>inline</ins> <del>static</del> const enumerated <i>C2</i> (<i>V2</i>);
<ins>inline</ins> <del>static</del> const enumerated <i>C3</i> (<i>V3</i>);
.....
</pre></blockquote>
</li>

<li><p>Change 17.4.2.1.4 [bitmask.types] as indicated:</p>

<blockquote>
<p>
-2- The bitmask type <tt><i>bitmask</i></tt> can be written:
</p>
<blockquote><pre>
[&hellip;]
<ins>inline</ins> constexpr bitmask C0(V0);
<ins>inline</ins> constexpr bitmask C1(V1);
<ins>inline</ins> constexpr bitmask C2(V2);
<ins>inline</ins> constexpr bitmask C3(V3);
</pre></blockquote>
</li>

<li><p>Change 18.6.1 [new.syn], header <tt>&lt;new&gt;</tt> synopsis, as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: The <em>removal</em> of the explicit <tt>static</tt> specifier for the namespace-scope
constants <tt>hardware_destructive_interference_size</tt> and <tt>hardware_constructive_interference_size</tt>  
is still <em>required</em> because adding <tt>inline</tt> alone would still not solve the ODR violation problem here.
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<blockquote><pre>
[&hellip;]
<i>// 18.6.5, hardware interference size</i>
<ins>inline</ins> <del>static</del> constexpr size_t hardware_destructive_interference_size = <i>implementation-defined</i>;
<ins>inline</ins> <del>static</del> constexpr size_t hardware_constructive_interference_size = <i>implementation-defined</i>;
</pre></blockquote>
</li>

<li><p>Change 18.6.5 [hardware.interference] as indicated:</p>

<blockquote><pre>
<ins>inline</ins> constexpr size_t hardware_destructive_interference_size = <i>implementation-defined</i>;
</pre>
<blockquote>
<p>
-1- [&hellip;]
</p>
</blockquote>
<pre>
<ins>inline</ins> constexpr size_t hardware_constructive_interference_size = <i>implementation-defined</i>;
</pre>
<blockquote>
<p>
-2- [&hellip;]
</p>
</blockquote>
</li>

<li><p>Change 19.5.1 [system_error.syn], header <tt>&lt;system_error&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
[&hellip;]
<i>// 19.5, system error support</i>
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_error_code_enum_v
  = is_error_code_enum&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_error_condition_enum_v
  = is_error_condition_enum&lt;T&gt;::value;
</pre></blockquote>
</li>

<li><p>Change 20.5.2 [tuple.syn], header <tt>&lt;tuple&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
[&hellip;]
<i>// 20.5.3.6, tuple helper classes</i>
template &lt;class T&gt;
  <ins>inline</ins> constexpr size_t tuple_size_v = tuple_size&lt;T&gt;::value;
</pre></blockquote>
</li>

<li><p>Change 20.7.2 [variant.syn], header <tt>&lt;variant&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
template &lt;class T&gt;
  <ins>inline</ins> constexpr size_t variant_size_v = variant_size&lt;T&gt;::value;

[&hellip;]

<ins>inline</ins> constexpr size_t variant_npos = -1;
</pre></blockquote>
</li>

<li><p>Change 20.10.2 [memory.syn], header <tt>&lt;memory&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<i>// 20.10.7.1, uses_allocator</i>
template &lt;class T, class Alloc&gt;
  <ins>inline</ins> constexpr bool uses_allocator_v = uses_allocator&lt;T, Alloc&gt;::value;
</pre></blockquote>
</li>

<li><p>Change 20.14.1 [functional.syn], header <tt>&lt;functional&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<i>// 20.14.11, function object binders</i>
template &lt;class T&gt;
  <ins>inline</ins> constexpr bool is_bind_expression_v = is_bind_expression&lt;T&gt;::value;
template &lt;class T&gt;
  <ins>inline</ins> constexpr int is_placeholder_v = is_placeholder&lt;T&gt;::value;
</pre></blockquote>
</li>

<li><p>Change 20.15.2 [meta.type.synop], header <tt>&lt;type_traits&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
[&hellip;]
<i>// 20.15.4.1, primary type categories</i>
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_void_v
  = is_void&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_null_pointer_v
  = is_null_pointer&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_integral_v
  = is_integral&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_floating_point_v
  = is_floating_point&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_array_v
  = is_array&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_pointer_v
  = is_pointer&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_lvalue_reference_v
  = is_lvalue_reference&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_rvalue_reference_v
  = is_rvalue_reference&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_member_object_pointer_v
  = is_member_object_pointer&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_member_function_pointer_v
  = is_member_function_pointer&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_enum_v
  = is_enum&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_union_v
  = is_union&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_class_v
  = is_class&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_function_v
  = is_function&lt;T&gt;::value;
  
<i>// 20.15.4.2, composite type categories</i>
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_reference_v
  = is_reference&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_arithmetic_v
  = is_arithmetic&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_fundamental_v
  = is_fundamental&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_object_v
   is_object&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_scalar_v
  = is_scalar&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_compound_v
  = is_compound&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_member_pointer_v
  = is_member_pointer&lt;T&gt;::value;
  
<i>// 20.15.4.3, type properties</i>
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_const_v
  = is_const&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_volatile_v
  = is_volatile&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivial_v
  = is_trivial&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivially_copyable_v
  = is_trivially_copyable&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_standard_layout_v
  = is_standard_layout&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_pod_v
  = is_pod&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_empty_v
  = is_empty&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_polymorphic_v
  = is_polymorphic&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_abstract_v
  = is_abstract&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_final_v
  = is_final&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_signed_v
  = is_signed&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_unsigned_v
  = is_unsigned&lt;T&gt;::value;
template &lt;class T, class... Args&gt; <ins>inline</ins> constexpr bool is_constructible_v
  = is_constructible&lt;T, Args...&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_default_constructible_v
  = is_default_constructible&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_copy_constructible_v
  = is_copy_constructible&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_move_constructible_v
  = is_move_constructible&lt;T&gt;::value;
template &lt;class T, class U&gt; <ins>inline</ins> constexpr bool is_assignable_v
  = is_assignable&lt;T, U&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_copy_assignable_v
  = is_copy_assignable&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_move_assignable_v
  = is_move_assignable&lt;T&gt;::value;
template &lt;class T, class U&gt; <ins>inline</ins> constexpr bool is_swappable_with_v
  = is_swappable_with&lt;T, U&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_swappable_v
  = is_swappable&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_destructible_v
  = is_destructible&lt;T&gt;::value;
template &lt;class T, class... Args&gt; <ins>inline</ins> constexpr bool is_trivially_constructible_v
  = is_trivially_constructible&lt;T, Args...&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivially_default_constructible_v
  = is_trivially_default_constructible&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivially_copy_constructible_v
  = is_trivially_copy_constructible&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivially_move_constructible_v
  = is_trivially_move_constructible&lt;T&gt;::value;
template &lt;class T, class U&gt; <ins>inline</ins> constexpr bool is_trivially_assignable_v
  = is_trivially_assignable&lt;T, U&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivially_copy_assignable_v
  = is_trivially_copy_assignable&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivially_move_assignable_v
  = is_trivially_move_assignable&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_trivially_destructible_v
  = is_trivially_destructible&lt;T&gt;::value;
template &lt;class T, class... Args&gt; <ins>inline</ins> constexpr bool is_nothrow_constructible_v
  = is_nothrow_constructible&lt;T, Args...&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_nothrow_default_constructible_v
  = is_nothrow_default_constructible&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_nothrow_copy_constructible_v
  = is_nothrow_copy_constructible&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_nothrow_move_constructible_v
  = is_nothrow_move_constructible&lt;T&gt;::value;
template &lt;class T, class U&gt; <ins>inline</ins> constexpr bool is_nothrow_assignable_v
  = is_nothrow_assignable&lt;T, U&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_nothrow_copy_assignable_v
  = is_nothrow_copy_assignable&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_nothrow_move_assignable_v
  = is_nothrow_move_assignable&lt;T&gt;::value;
template &lt;class T, class U&gt; <ins>inline</ins> constexpr bool is_nothrow_swappable_with_v
  = is_nothrow_swappable_with&lt;T, U&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_nothrow_swappable_v
  = is_nothrow_swappable&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool is_nothrow_destructible_v
  = is_nothrow_destructible&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool has_virtual_destructor_v
  = has_virtual_destructor&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr bool has_unique_object_representations_v
  = has_unique_object_representations&lt;T&gt;::value;
  
<i>// 20.15.5, type property queries</i>
template &lt;class T&gt; <ins>inline</ins> constexpr size_t alignment_of_v
  = alignment_of&lt;T&gt;::value;
template &lt;class T&gt; <ins>inline</ins> constexpr size_t rank_v
  = rank&lt;T&gt;::value;
template &lt;class T, unsigned I = 0&gt; <ins>inline</ins> constexpr size_t extent_v
  = extent&lt;T, I&gt;::value;

<i>// 20.15.6, type relations</i>
template &lt;class T, class U&gt; <ins>inline</ins> constexpr bool is_same_v
  = is_same&lt;T, U&gt;::value;
template &lt;class Base, class Derived&gt; <ins>inline</ins> constexpr bool is_base_of_v
  = is_base_of&lt;Base, Derived&gt;::value;
template &lt;class From, class To&gt; <ins>inline</ins> constexpr bool is_convertible_v
  = is_convertible&lt;From, To&gt;::value;
template &lt;class T, class R = void&gt; <ins>inline</ins> constexpr bool is_callable_v
  = is_callable&lt;T, R&gt;::value;
template &lt;class T, class R = void&gt; <ins>inline</ins> constexpr bool is_nothrow_callable_v
  = is_nothrow_callable&lt;T, R&gt;::value;
  
<i>// 20.15.8, logical operator traits</i>
template&lt;class... B&gt; <ins>inline</ins> constexpr bool conjunction_v = conjunction&lt;B...&gt;::value;
template&lt;class... B&gt; <ins>inline</ins> constexpr bool disjunction_v = disjunction&lt;B...&gt;::value;
template&lt;class B&gt; <ins>inline</ins> constexpr bool negation_v = negation&lt;B&gt;::value;
</pre></blockquote>
</li>

<li><p>Change 20.16.2 [ratio.syn], header <tt>&lt;ratio&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
template &lt;class R1, class R2&gt;
  <ins>inline</ins> constexpr bool ratio_equal_v = ratio_equal&lt;R1, R2&gt;::value;
template &lt;class R1, class R2&gt;
  <ins>inline</ins> constexpr bool ratio_not_equal_v = ratio_not_equal&lt;R1, R2&gt;::value;
template &lt;class R1, class R2&gt;
  <ins>inline</ins> constexpr bool ratio_less_v = ratio_less&lt;R1, R2&gt;::value;
template &lt;class R1, class R2&gt;
  <ins>inline</ins> constexpr bool ratio_less_equal_v = ratio_less_equal&lt;R1, R2&gt;::value;
template &lt;class R1, class R2&gt;
  <ins>inline</ins> constexpr bool ratio_greater_v = ratio_greater&lt;R1, R2&gt;::value;
template &lt;class R1, class R2&gt;
  <ins>inline</ins> constexpr bool ratio_greater_equal_v = ratio_greater_equal&lt;R1, R2&gt;::value;
</pre></blockquote>
</li>

<li><p>Change 20.17.2 [time.syn], header <tt>&lt;chrono&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
<i>// 20.17.4, customization traits</i>
template &lt;class Rep&gt; struct treat_as_floating_point;
template &lt;class Rep&gt; struct duration_values;
template &lt;class Rep&gt; <ins>inline</ins> constexpr bool treat_as_floating_point_v
  = treat_as_floating_point&lt;Rep&gt;::value;
</pre></blockquote>
</li>

<li><p>Change 20.19.2 [execution.syn], header <tt>&lt;execution&gt;</tt> synopsis, as indicated:</p>

<blockquote><pre>
namespace std {
  <i>// 20.19.3, execution policy type trait</i>
  template&lt;class T&gt; struct is_execution_policy;
  template&lt;class T&gt; <ins>inline</ins> constexpr bool is_execution_policy_v = is_execution_policy&lt;T&gt;::value;
}
</pre></blockquote>
</li>

<li><p>Change 28.5.1 [re.synopt], bitmask type <tt>syntax_option_type</tt> synopsis, as indicated:</p>

<blockquote><pre>
namespace std::regex_constants {
  using syntax_option_type = <i>T1</i>;
  <ins>inline</ins> constexpr syntax_option_type icase = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type nosubs = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type optimize = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type collate = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type ECMAScript = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type basic = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type extended = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type awk = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type grep = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type egrep = <i>unspecified</i>;
  <ins>inline</ins> constexpr syntax_option_type multiline = <i>unspecified</i>;
}
</pre></blockquote>
</li>

<li><p>Change 28.5.2 [re.matchflag], bitmask type <tt>match_flag_type</tt> synopsis, as indicated:</p>

<blockquote><pre>
namespace std::regex_constants {
  using match_flag_type = <i>T2</i>;
  <ins>inline</ins> constexpr match_flag_type match_default = {};
  <ins>inline</ins> constexpr match_flag_type match_not_bol = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_eol = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_bow = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_eow = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_any = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_not_null = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_continuous = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type match_prev_avail = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type format_default = {};
  <ins>inline</ins> constexpr match_flag_type format_sed = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type format_no_copy = <i>unspecified</i>;
  <ins>inline</ins> constexpr match_flag_type format_first_only = <i>unspecified</i>;
}
</pre></blockquote>
</li>

<li><p>Change 28.5.3 [re.err], <tt>error_type</tt> synopsis, as indicated:</p>

<blockquote><pre>
namespace std::regex_constants {
  using error_type = <i>T3</i>;
  <ins>inline</ins> constexpr error_type error_collate = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_ctype = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_escape = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_backref = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_brack = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_paren = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_brace = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_badbrace = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_range = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_space = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_badrepeat = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_complexity = <i>unspecified</i>;
  <ins>inline</ins> constexpr error_type error_stack = <i>unspecified</i>;
}
</pre></blockquote>
</li>

</ol>

</li>
</ol>

<h2><a name="Akn"></a>Acknowledgements</h2>
<p>
I would like to thank Richard Smith for clarifying core-language relevant matters and
for his generous acceptance even of the huge editorial changes that would result when option
(B2) would be voted in.
</p>

</body></html>