<!DOCTYPE html><html><head>
      <title>properties</title>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      
      
        <script type="text/x-mathjax-config">
          MathJax.Hub.Config({"extensions":["tex2jax.js"],"jax":["input/TeX","output/HTML-CSS"],"messageStyle":"none","tex2jax":{"processEnvironments":false,"processEscapes":true,"inlineMath":[["$","$"],["\\(","\\)"]],"displayMath":[["$$","$$"],["\\[","\\]"]]},"TeX":{"extensions":["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]},"HTML-CSS":{"availableFonts":["TeX"]}});
        </script>
        <script type="text/javascript" async src="file:////Users/dshollm/.vscode/extensions/shd101wyy.markdown-preview-enhanced-0.3.11/node_modules/@shd101wyy/mume/dependencies/mathjax/MathJax.js" charset="UTF-8"></script>
        
      
      
      
      
      
      
      
      
      

      <style> 
      /**
 * prism.js Github theme based on GitHub's theme.
 * @author Sam Clarke
 */
code[class*="language-"],
pre[class*="language-"] {
  color: #333;
  background: none;
  font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
  text-align: left;
  white-space: pre;
  word-spacing: normal;
  word-break: normal;
  word-wrap: normal;
  line-height: 1.4;

  -moz-tab-size: 8;
  -o-tab-size: 8;
  tab-size: 8;

  -webkit-hyphens: none;
  -moz-hyphens: none;
  -ms-hyphens: none;
  hyphens: none;
}

/* Code blocks */
pre[class*="language-"] {
  padding: .8em;
  overflow: auto;
  /* border: 1px solid #ddd; */
  border-radius: 3px;
  /* background: #fff; */
  background: #f5f5f5;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
  padding: .1em;
  border-radius: .3em;
  white-space: normal;
  background: #f5f5f5;
}

.token.comment,
.token.blockquote {
  color: #969896;
}

.token.cdata {
  color: #183691;
}

.token.doctype,
.token.punctuation,
.token.variable,
.token.macro.property {
  color: #333;
}

.token.operator,
.token.important,
.token.keyword,
.token.rule,
.token.builtin {
  color: #a71d5d;
}

.token.string,
.token.url,
.token.regex,
.token.attr-value {
  color: #183691;
}

.token.property,
.token.number,
.token.boolean,
.token.entity,
.token.atrule,
.token.constant,
.token.symbol,
.token.command,
.token.code {
  color: #0086b3;
}

.token.tag,
.token.selector,
.token.prolog {
  color: #63a35c;
}

.token.function,
.token.namespace,
.token.pseudo-element,
.token.class,
.token.class-name,
.token.pseudo-class,
.token.id,
.token.url-reference .token.variable,
.token.attr-name {
  color: #795da3;
}

.token.entity {
  cursor: help;
}

.token.title,
.token.title .token.punctuation {
  font-weight: bold;
  color: #1d3e81;
}

.token.list {
  color: #ed6a43;
}

.token.inserted {
  background-color: #eaffea;
  color: #55a532;
}

.token.deleted {
  background-color: #ffecec;
  color: #bd2c00;
}

.token.bold {
  font-weight: bold;
}

.token.italic {
  font-style: italic;
}


/* JSON */
.language-json .token.property {
  color: #183691;
}

.language-markup .token.tag .token.punctuation {
  color: #333;
}

/* CSS */
code.language-css,
.language-css .token.function {
  color: #0086b3;
}

/* YAML */
.language-yaml .token.atrule {
  color: #63a35c;
}

code.language-yaml {
  color: #183691;
}

/* Ruby */
.language-ruby .token.function {
  color: #333;
}

/* Markdown */
.language-markdown .token.url {
  color: #795da3;
}

/* Makefile */
.language-makefile .token.symbol {
  color: #795da3;
}

.language-makefile .token.variable {
  color: #183691;
}

.language-makefile .token.builtin {
  color: #0086b3;
}

/* Bash */
.language-bash .token.keyword {
  color: #0086b3;
}html body{font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.6;color:#333;background-color:#fff;overflow:initial;box-sizing:border-box;word-wrap:break-word}html body>:first-child{margin-top:0}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{line-height:1.2;margin-top:1em;margin-bottom:16px;color:#000}html body h1{font-size:2.25em;font-weight:300;padding-bottom:.3em}html body h2{font-size:1.75em;font-weight:400;padding-bottom:.3em}html body h3{font-size:1.5em;font-weight:500}html body h4{font-size:1.25em;font-weight:600}html body h5{font-size:1.1em;font-weight:600}html body h6{font-size:1em;font-weight:600}html body h1,html body h2,html body h3,html body h4,html body h5{font-weight:600}html body h5{font-size:1em}html body h6{color:#5c5c5c}html body strong{color:#000}html body del{color:#5c5c5c}html body a:not([href]){color:inherit;text-decoration:none}html body a{color:#08c;text-decoration:none}html body a:hover{color:#00a3f5;text-decoration:none}html body img{max-width:100%}html body>p{margin-top:0;margin-bottom:16px;word-wrap:break-word}html body>ul,html body>ol{margin-bottom:16px}html body ul,html body ol{padding-left:2em}html body ul.no-list,html body ol.no-list{padding:0;list-style-type:none}html body ul ul,html body ul ol,html body ol ol,html body ol ul{margin-top:0;margin-bottom:0}html body li{margin-bottom:0}html body li.task-list-item{list-style:none}html body li>p{margin-top:0;margin-bottom:0}html body .task-list-item-checkbox{margin:0 .2em .25em -1.8em;vertical-align:middle}html body .task-list-item-checkbox:hover{cursor:pointer}html body blockquote{margin:16px 0;font-size:inherit;padding:0 15px;color:#5c5c5c;border-left:4px solid #d6d6d6}html body blockquote>:first-child{margin-top:0}html body blockquote>:last-child{margin-bottom:0}html body hr{height:4px;margin:32px 0;background-color:#d6d6d6;border:0 none}html body table{margin:10px 0 15px 0;border-collapse:collapse;border-spacing:0;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}html body table th{font-weight:bold;color:#000}html body table td,html body table th{border:1px solid #d6d6d6;padding:6px 13px}html body dl{padding:0}html body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:bold}html body dl dd{padding:0 16px;margin-bottom:16px}html body code{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:.85em !important;color:#000;background-color:#f0f0f0;border-radius:3px;padding:.2em 0}html body code::before,html body code::after{letter-spacing:-0.2em;content:"\00a0"}html body pre>code{padding:0;margin:0;font-size:.85em !important;word-break:normal;white-space:pre;background:transparent;border:0}html body .highlight{margin-bottom:16px}html body .highlight pre,html body pre{padding:1em;overflow:auto;font-size:.85em !important;line-height:1.45;border:#d6d6d6;border-radius:3px}html body .highlight pre{margin-bottom:0;word-break:normal}html body pre code,html body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}html body pre code:before,html body pre tt:before,html body pre code:after,html body pre tt:after{content:normal}html body p,html body blockquote,html body ul,html body ol,html body dl,html body pre{margin-top:0;margin-bottom:16px}html body kbd{color:#000;border:1px solid #d6d6d6;border-bottom:2px solid #c7c7c7;padding:2px 4px;background-color:#f0f0f0;border-radius:3px}@media print{html body{background-color:#fff}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{color:#000;page-break-after:avoid}html body blockquote{color:#5c5c5c}html body pre{page-break-inside:avoid}html body table{display:table}html body img{display:block;max-width:100%;max-height:100%}html body pre,html body code{word-wrap:break-word;white-space:pre}}.markdown-preview{width:100%;height:100%;box-sizing:border-box}.markdown-preview .pagebreak,.markdown-preview .newpage{page-break-before:always}.markdown-preview pre.line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}.markdown-preview pre.line-numbers>code{position:relative}.markdown-preview pre.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:1em;font-size:100%;left:0;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.markdown-preview pre.line-numbers .line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.markdown-preview pre.line-numbers .line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.markdown-preview .mathjax-exps .MathJax_Display{text-align:center !important}.markdown-preview:not([for="preview"]) .code-chunk .btn-group{display:none}.markdown-preview:not([for="preview"]) .code-chunk .status{display:none}.markdown-preview:not([for="preview"]) .code-chunk .output-div{margin-bottom:16px}.scrollbar-style::-webkit-scrollbar{width:8px}.scrollbar-style::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}.scrollbar-style::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode]){position:relative;width:100%;height:100%;top:0;left:0;margin:0;padding:0;overflow:auto}html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{position:relative;top:0}@media screen and (min-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em calc(50% - 457px)}}@media screen and (max-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{font-size:14px !important;padding:1em}}@media print{html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{display:none}}html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{position:fixed;bottom:8px;left:8px;font-size:28px;cursor:pointer;color:inherit;z-index:99;width:32px;text-align:center;opacity:.4}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] #sidebar-toc-btn{opacity:1}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc{position:fixed;top:0;left:0;width:300px;height:100%;padding:32px 0 48px 0;font-size:14px;box-shadow:0 0 4px rgba(150,150,150,0.33);box-sizing:border-box;overflow:auto;background-color:inherit}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar{width:8px}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc a{text-decoration:none}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul{padding:0 1.6em;margin-top:.8em}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc li{margin-bottom:.8em}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul{list-style-type:none}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{left:300px;width:calc(100% -  300px);padding:2em calc(50% - 457px -  150px);margin:0;box-sizing:border-box}@media screen and (max-width:1274px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{width:100%}}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .markdown-preview{left:50%;transform:translateX(-50%)}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .md-sidebar-toc{display:none}
 
      </style>
    </head>
    <body for="html-export">
      <div class="mume markdown-preview   ">
      <table style="width:79%;">
<colgroup>
<col style="width: 27%">
<col style="width: 51%">
</colgroup>
<tbody>
<tr class="odd">
<td style="text-align: left;">Title:</td>
<td>A General Property Customization Mechanism</td>
</tr>
<tr class="even">
<td style="text-align: left;">Authors:</td>
<td>David Hollman, dshollm@sandia.gov</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td>Chris Kohlhoff, chris@kohlhoff.com</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td>Bryce Lelbach, brycelelbach@gmail.com</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td>Jared Hoberock, jhoberock@nvidia.com</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td>Gordon Brown, gordon@codeplay.com</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td>Micha&#x142; Dominiak, griwes@griwes.info</td>
</tr>
<tr class="even">
<td style="text-align: left;">Other Contributors:</td>
<td>Lee Howes, lwh@fb.com</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td>Michael Garland, mgarland@nvidia.com</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td>Chris Mysen, mysen@google.com</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td>Thomas Rodgers, rodgert@twrodgers.com</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td>Michael Wong, michael@codeplay.com</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Document Number:</td>
<td>P1393R0</td>
</tr>
<tr class="even">
<td style="text-align: left;">Date:</td>
<td>2019-01-13</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Audience:</td>
<td>LEWG</td>
</tr>
<tr class="even">
<td style="text-align: left;">Reply-to:</td>
<td>sg1-exec@googlegroups.com</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Abstract:</td>
<td>This paper generalizes and extracts the property customization mechanism from <a href="http://wg21.link/p0443r8">P0443r8</a>, as requested by LEWG in the 2018-11 San Diego meeting. This document does not introduce any significant design changes from the design previously discussed in the context of P0443; the separation herein is merely a recognition of the mechanism&#x2019;s general applicability and is made in anticipation of its use in other contexts.</td>
</tr>
</tbody>
</table>
<h2 id="changelog">Changelog</h2>
<h3 id="revision-0">Revision 0</h3>
<ul>
<li>Initial design, migrated from P0443R9.</li>
</ul>
<h1 id="introduction">Introduction</h1>
<p>At the 2018-11 San Diego meeting, LEWG voted to generalize the mechanism for property-based customization that P0443R9 introduced. They requested that the customization points objects for handling properties be moved to the namespace <code>std</code> (from namespace <code>std::execution</code>), and that a paper presenting wording for the mechanism in a manner decoupled from executors be brought to the 2019-02 Kona meeting. LEWG further requested that a separate customization point object be provided for properties that are intended to enforce the presence of a particular interface, and this paper includes that object as <code>require_concept</code>. The requested changes have been provided here. Discussion pertaining to the design of this mechanism has been omitted here, since significant background and discussion has been included in previous revisions of P0443 and meeting notes on the discussion thereof.</p>
<h1 id="proposed-wording">Proposed Wording</h1>
<p>Add the following row to the table in <strong>[utilities.general]</strong>:</p>
<table>
<colgroup>
<col style="width: 19%">
<col style="width: 64%">
<col style="width: 16%">
</colgroup>
<tbody>
<tr class="odd">
<td></td>
<td style="text-align: left;"><strong>Subclause</strong></td>
<td style="text-align: left;"><strong>Header(s)</strong></td>
</tr>
<tr class="even">
<td>[properties]</td>
<td style="text-align: left;">Support for the property customization mechanism</td>
<td style="text-align: left;"><code>&lt;property&gt;</code></td>
</tr>
</tbody>
</table>
<p>Add the following subclause to <strong>[utilities]</strong> in a section which the editor shall determine:</p>
<h2 id="properties-support">Properties Support</h2>
<h3 id="general">General</h3>
<p>This subclause describes components supporting an extensible customization mechanism, currently used most prominently by the execution support library <strong>[execution]</strong>.</p>
<h3 id="header-property-synopsis">Header <code>&lt;property&gt;</code> synopsis</h3>
<pre class="text language-text" data-role="codeBlock" data-info="text"><code>namespace std {

  // Customization point objects:

  inline namespace unspecified {
    inline constexpr unspecified require_concept = unspecified;
    inline constexpr unspecified require = unspecified;
    inline constexpr unspecified prefer = unspecified;
    inline constexpr unspecified query = unspecified;
  }

  // Property applicability trait:
  template&lt;class T, class P&gt; struct is_applicable_property;

  template&lt;class T, class Property&gt;
    inline constexpr bool is_applicable_property_v = is_applicable_property&lt;T, Property&gt;::value;

  // Customization point type traits:
  template&lt;class T, class P&gt; struct can_require_concept;
  template&lt;class T, class... P&gt; struct can_require;
  template&lt;class T, class... P&gt; struct can_prefer;
  template&lt;class T, class P&gt; struct can_query;

  template&lt;class T, class Property&gt;
    inline constexpr bool can_require_concept_v = can_require_concept&lt;T, Property&gt;::value;
  template&lt;class T, class... Properties&gt;
    inline constexpr bool can_require_v = can_require&lt;T, Properties...&gt;::value;
  template&lt;class T, class... Properties&gt;
    inline constexpr bool can_prefer_v = can_prefer&lt;T, Properties...&gt;::value;
  template&lt;class T, class Property&gt;
    inline constexpr bool can_query_v = can_query&lt;T, Property&gt;::value;

} // namespace std</code></pre>
<h2 id="customization-point-objects">Customization point objects</h2>
<h3 id="require_concept"><code>require_concept</code></h3>
<pre class="text language-text language-cpp" data-role="codeBlock" data-info="c++"><span class="token keyword">inline</span> <span class="token keyword">namespace</span> unspecified <span class="token punctuation">{</span>
  <span class="token keyword">inline</span> <span class="token keyword">constexpr</span> unspecified require_concept <span class="token operator">=</span> unspecified<span class="token punctuation">;</span>
<span class="token punctuation">}</span></pre>
<p>The name <code>require_concept</code> denotes a customization point object. The expression <code>std::require_concept(E, P)</code> for some subexpressions <code>E</code> and <code>P</code> (with types <code>T = decay_t&lt;decltype(E)&gt;</code> and <code>Prop = decay_t&lt;decltype(P)&gt;</code>) is expression-equivalent to:</p>
<ul>
<li><p>If <code>is_applicable_property_v&lt;T, Prop&gt; &amp;&amp; Prop::is_requirable_concept</code> is not a well-formed constant expression with value <code>true</code>, <code>std::require_concept(E, P)</code> is ill-formed.</p></li>
<li><p>Otherwise, <code>E</code> if the expression <code>Prop::template static_query_v&lt;T&gt; == Prop::value()</code> is a well-formed constant expression with value <code>true</code>.</p></li>
<li><p>Otherwise, <code>(E).require_concept(P)</code> if the expression <code>(E).require_concept(P)</code> is well-formed.</p></li>
<li><p>Otherwise, <code>require_concept(E, P)</code> if the expression <code>require_concept(E, P)</code> is a valid expression with overload resolution performed in a context that does not include the declaration of the <code>require_concept</code> customization point object.</p></li>
<li><p>Otherwise, <code>std::require_concept(E, P)</code> is ill-formed.</p></li>
</ul>
<h3 id="require"><code>require</code></h3>
<pre class="text language-text language-cpp" data-role="codeBlock" data-info="c++"><span class="token keyword">inline</span> <span class="token keyword">namespace</span> unspecified <span class="token punctuation">{</span>
  <span class="token keyword">inline</span> <span class="token keyword">constexpr</span> unspecified require <span class="token operator">=</span> unspecified<span class="token punctuation">;</span>
<span class="token punctuation">}</span></pre>
<p>The name <code>require</code> denotes a customization point object. The expression <code>std::require(E, P0, Pn...)</code> for some subexpressions <code>E</code> and <code>P0</code>, and where <code>Pn...</code> represents <code>N</code> subexpressions (where <code>N</code> is 0 or more, and with types <code>T = decay_t&lt;decltype(E)&gt;</code> and <code>Prop0 = decay_t&lt;decltype(P0)&gt;</code>) is expression-equivalent to:</p>
<ul>
<li><p>If <code>is_applicable_property_v&lt;T, Prop0&gt; &amp;&amp; Prop0::is_requirable</code> is not a well-formed constant expression with value <code>true</code>, <code>std::require(E, P0, Pn...)</code> is ill-formed.</p></li>
<li><p>Otherwise, <code>E</code> if <code>N == 0</code> and the expression <code>Prop0::template static_query_v&lt;T&gt; == Prop0::value()</code> is a well-formed constant expression with value <code>true</code>.</p></li>
<li><p>Otherwise, <code>(E).require(P0)</code> if <code>N == 0</code> and the expression <code>(E).require(P0)</code> is a valid expression.</p></li>
<li><p>Otherwise, <code>require(E, P)</code> if <code>N == 0</code> and the expression <code>require(E, P)</code> is a valid expression with overload resolution performed in a context that does not include the declaration of the <code>require</code> customization point object.</p></li>
<li><p>Otherwise, <code>std::require(std::require(E, P0), Pn...)</code> if <code>N &gt; 0</code> and the expression <code>std::require(std::require(E, P0), Pn...)</code> is a valid expression.</p></li>
<li><p>Otherwise, <code>std::require(E, P0, Pn...)</code> is ill-formed.</p></li>
</ul>
<h3 id="prefer"><code>prefer</code></h3>
<pre class="text language-text language-cpp" data-role="codeBlock" data-info="c++"><span class="token keyword">inline</span> <span class="token keyword">namespace</span> unspecified <span class="token punctuation">{</span>
  <span class="token keyword">inline</span> <span class="token keyword">constexpr</span> unspecified prefer <span class="token operator">=</span> unspecified<span class="token punctuation">;</span>
<span class="token punctuation">}</span></pre>
<p>The name <code>prefer</code> denotes a customization point object. The expression <code>std::prefer(E, P0, Pn...)</code> for some subexpressions <code>E</code> and <code>P0</code>, and where <code>Pn...</code> represents <code>N</code> subexpressions (where <code>N</code> is 0 or more, and with types <code>T = decay_t&lt;decltype(E)&gt;</code> and <code>Prop0 = decay_t&lt;decltype(P0)&gt;</code>) is expression-equivalent to:</p>
<ul>
<li><p>If <code>is_applicable_property_v&lt;T, Prop0&gt; &amp;&amp; Prop0::is_preferable</code> is not a well-formed constant expression with value <code>true</code>, <code>std::prefer(E, P0, Pn...)</code> is ill-formed.</p></li>
<li><p>Otherwise, <code>E</code> if <code>N == 0</code> and the expression <code>Prop0::template static_query_v&lt;T&gt; == Prop0::value()</code> is a well-formed constant expression with value <code>true</code>.</p></li>
<li><p>Otherwise, <code>(E).require(P0)</code> if <code>N == 0</code> and the expression <code>(E).require(P0)</code> is a valid expression.</p></li>
<li><p>Otherwise, <code>require(E, P0)</code> if <code>N == 0</code> and the expression <code>require(E, P0)</code> is a valid expression with overload resolution performed in a context that does not include the declaration of the <code>require</code> customization point object.</p></li>
<li><p>Otherwise, <code>std::prefer(std::prefer(E, P0), Pn...)</code> if <code>N &gt; 0</code> and the expression <code>std::prefer(std::prefer(E, P0), Pn...)</code> is a valid expression.</p></li>
<li><p>Otherwise, <code>std::prefer(E, P0, Pn...)</code> is ill-formed.</p></li>
</ul>
<h3 id="query"><code>query</code></h3>
<pre class="text language-text language-cpp" data-role="codeBlock" data-info="c++"><span class="token keyword">inline</span> <span class="token keyword">namespace</span> unspecified <span class="token punctuation">{</span>
  <span class="token keyword">inline</span> <span class="token keyword">constexpr</span> unspecified query <span class="token operator">=</span> unspecified<span class="token punctuation">;</span>
<span class="token punctuation">}</span></pre>
<p>The name <code>query</code> denotes a customization point object. The expression <code>std::query(E, P)</code> for some subexpressions <code>E</code> and <code>P</code> (with types <code>T = decay_t&lt;decltype(E)&gt;</code> and <code>Prop = decay_t&lt;decltype(P)&gt;</code>) is expression-equivalent to:</p>
<ul>
<li><p>If <code>is_applicable_property_v&lt;T, Prop&gt;</code> is not a well-formed constant expression with value <code>true</code>, <code>std::query(E, P)</code> is ill-formed.</p></li>
<li><p>Otherwise, <code>Prop::template static_query_v&lt;T&gt;</code> if the expression <code>Prop::template static_query_v&lt;T&gt;</code> is a well-formed constant expression.</p></li>
<li><p>Otherwise, <code>(E).query(P)</code> if the expression <code>(E).query(P)</code> is well-formed.</p></li>
<li><p>Otherwise, <code>query(E, P)</code> if the expression <code>query(E, P)</code> is a valid expression with overload resolution performed in a context that does not include the declaration of the <code>query</code> customization point object.</p></li>
<li><p>Otherwise, <code>std::query(E, P)</code> is ill-formed.</p></li>
</ul>
<h2 id="property-applicability-trait">Property applicability trait</h2>
<pre class="text language-text language-cpp" data-role="codeBlock" data-info="c++"><span class="token keyword">template</span><span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Property</span><span class="token operator">&gt;</span> <span class="token keyword">struct</span> is_applicable_property<span class="token punctuation">;</span></pre>
<p>This sub-clause contains a template that may be used to query the applicability of a property to a type at compile time. It may be specialized to indicate applicability of a property to a type. This template is a UnaryTypeTrait (C++Std [meta.rqmts]) with a BaseCharacteristic of <code>true_type</code> if the corresponding condition is true, otherwise <code>false_type</code>.</p>
<table>
<colgroup>
<col style="width: 43%">
<col style="width: 32%">
<col style="width: 24%">
</colgroup>
<thead>
<tr class="header">
<th>Template</th>
<th>Condition</th>
<th>Preconditions</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>template&lt;class T, class P&gt;</code> <br><code>struct is_applicable_property</code></td>
<td>The expression <code>P::template is_applicable_property_v&lt;T&gt;</code> is a well-formed constant expression with a value of <code>true</code>.</td>
<td><code>P</code> and <code>T</code> are complete types.</td>
</tr>
</tbody>
</table>
<h2 id="customization-point-type-traits">Customization point type traits</h2>
<pre class="text language-text language-cpp" data-role="codeBlock" data-info="c++"><span class="token keyword">template</span><span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Property</span><span class="token operator">&gt;</span> <span class="token keyword">struct</span> can_require_concept<span class="token punctuation">;</span>
<span class="token keyword">template</span><span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> Properties<span class="token operator">&gt;</span> <span class="token keyword">struct</span> can_require<span class="token punctuation">;</span>
<span class="token keyword">template</span><span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> Properties<span class="token operator">&gt;</span> <span class="token keyword">struct</span> can_prefer<span class="token punctuation">;</span>
<span class="token keyword">template</span><span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token keyword">class</span> <span class="token class-name">Property</span><span class="token operator">&gt;</span> <span class="token keyword">struct</span> can_query<span class="token punctuation">;</span></pre>
<p>This sub-clause contains templates that may be used to query the validity of the application of property customization point objects to a type at compile time. Each of these templates is a UnaryTypeTrait (C++Std [meta.rqmts]) with a BaseCharacteristic of <code>true_type</code> if the corresponding condition is true, otherwise <code>false_type</code>.</p>
<table>
<colgroup>
<col style="width: 43%">
<col style="width: 32%">
<col style="width: 24%">
</colgroup>
<thead>
<tr class="header">
<th>Template</th>
<th>Condition</th>
<th>Preconditions</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>template&lt;class T, class P&gt;</code> <br><code>struct can_require_concept</code></td>
<td>The expression <code>std::require_concept(declval&lt;const T&gt;(), declval&lt;P&gt;())</code> is well-formed.</td>
<td><code>T</code> and <code>P</code> are complete types.</td>
</tr>
<tr class="even">
<td><code>template&lt;class T, class... P&gt;</code> <br><code>struct can_require</code></td>
<td>The expression <code>std::require(declval&lt;const T&gt;(), declval&lt;P&gt;()...)</code> is well-formed.</td>
<td><code>T</code> and <code>P...</code> are complete types.</td>
</tr>
<tr class="odd">
<td><code>template&lt;class T, class... P&gt;</code> <br><code>struct can_prefer</code></td>
<td>The expression <code>std::prefer(declval&lt;const T&gt;(), declval&lt;P&gt;()...)</code> is well-formed.</td>
<td><code>T</code> and <code>P...</code> are complete types.</td>
</tr>
<tr class="even">
<td><code>template&lt;class T, class P&gt;</code> <br><code>struct can_query</code></td>
<td>The expression <code>std::query(declval&lt;const T&gt;(), declval&lt;P&gt;())</code> is well-formed.</td>
<td><code>T</code> and <code>P</code> are complete types.</td>
</tr>
<tr class="odd">
<td><code>template&lt;class T, class P&gt;</code> <br><code>struct is_applicable_property</code></td>
<td>The expression <code>P::template is_applicable_property_v&lt;T&gt;</code> is a well-formed constant expression with a value of <code>true</code>.</td>
<td><code>P</code> and <code>T</code> are complete types.</td>
</tr>
</tbody>
</table>
<h2 id="the-property-customization-mechanism">The property customization mechanism</h2>
<h3 id="in-general">In general</h3>
<p>When the property customization mechanism is being employed for some library facility, an object&#x2019;s behavior and effects on that facility in generic contexts may be determined by a set of applicable properties, and each property imposes certain requirements on that object&#x2019;s behavior or exposes some attribute of that object. As well as modifying the behavior of an object, properties can be applied to an object to enforce the presence of an interface, potentially resulting in an object of a new type that satisfies some concept associated with that property.</p>
<h3 id="requirements-on-properties">Requirements on properties</h3>
<ul>
<li><p>A property type <code>P</code> shall provide a nested constant variable template named <code>is_applicable_property_v</code>, usable as <code>P::template is_applicable_property_v&lt;T&gt;</code> on any complete type <code>T</code>, with a value of type <code>bool</code>.</p></li>
<li>A property type shall be either a concept-preserving property type or a concept-enforcing property type.
<ul>
<li>A <dfn>concept-preserving property</dfn> type <code>PN</code> shall provide:
<ul>
<li>A nested constant expression named <code>is_requirable</code> of type <code>bool</code>, usable as <code>PN::is_requirable</code>.</li>
<li>A nested constant expression named <code>is_preferable</code> of type <code>bool</code>, usable as <code>PN::is_preferable</code>.</li>
</ul></li>
<li>A <dfn>concept-enforcing property</dfn> type <code>PC</code> that shall provide a nested constant expression named <code>is_requirable_concept</code> of type <code>bool</code>, usable as <code>PC::is_requirable_concept</code>.</li>
</ul></li>
<li><p>A property type <code>P</code> may provide a nested type <code>polymorphic_query_result_type</code> that satisfies the <code>CopyConstructible</code> and <code>Destructible</code> requirements. If <code>P</code> is a concept-preserving property, and <code>P::is_requirable == true</code> or <code>P::is_preferable == true</code>, then <code>polymorphic_query_result_type</code> shall also satisfy the <code>DefaultConstructible</code> requirements when provided. [<em>Note:</em> When present, this type allows the property to be used with polymorphic wrappers. <em>&#x2013;end note</em>]</p></li>
<li>A property type <code>P</code> may provide:
<ul>
<li>A nested variable template <code>static_query_v</code>, usable as <code>P::template static_query_v&lt;T&gt;</code> for any type <code>T</code> where <code>is_applicable_property_v&lt;T, P&gt;</code> is <code>true</code>. [<em>Note:</em> This may be conditionally present. <em>&#x2014;end note</em>]</li>
<li>A member function <code>value()</code>.</li>
</ul></li>
<li><p>For a property type <code>P</code> and type <code>T</code> where <code>is_applicable_property_v&lt;T, P&gt;</code> is <code>true</code>, if <code>P::value()</code> is a valid expression of type <code>V1</code> and <code>P::template static_query_v&lt;T&gt;</code> is a valid constant expression of type <code>V2</code>, then <code>V1</code> and <code>V2</code> shall meet the requirements of <code>EqualityComparableWith&lt;V1, V2&gt;</code> in <strong>[concept.equalitycomparable]</strong>.</p></li>
<li><p>[<em>Note:</em> The <code>static_query_v</code> and <code>value()</code> members are used to determine whether invoking <code>require</code> or <code>require_concept</code> would result in an identity transformation. <em>&#x2014;end note</em>]</p></li>
<li>A concept-enforcing property type <code>P</code> may provide a nested template or named <code>polymorphic_wrapper_type</code>, usable with properties <code>Ps...</code> as <code>typename P::template polymorphic_wrapper_type&lt;Ps...&gt;</code>. The type <code>PW</code> resulting from the instantiation of this template shall:
<ul>
<li>be implicitly constructible from a (potentially <code>const</code>) instance of a type <code>T</code>, where:
<ul>
<li><code>can_query_v&lt;Pn, T&gt;</code> is <code>true</code> for all <code>Pn</code> in <code>Ps...</code> where <code>Pn::polymorhic_query_result_type</code> is well-formed</li>
<li>for all <code>Pn</code> in <code>Ps...</code> with <code>Pn::is_requirable == true</code>, either:
<ul>
<li><code>can_require_v&lt;Pn, T&gt;</code> is <code>true</code>, or</li>
<li><code>can_prefer_v&lt;Pn, T&gt;</code> is <code>true</code></li>
</ul></li>
<li><code>can_prefer_v&lt;Pn, T&gt;</code> is <code>true</code> for all <code>Pn</code> in <code>Ps...</code> with <code>Pn::is_preferable == true</code></li>
<li><code>P::template static_query_v&lt;T&gt; == P::value()</code> is true if <code>P::template static_query_v&lt;T&gt; == P::value()</code> is a valid constant expression</li>
</ul></li>
<li>be valid in the constant expression <code>is_applicable_property_v&lt;PW, P&gt;</code>, and that expression shall be <code>true</code>.</li>
<li>if <code>P::template static_query_v&lt;PW&gt; == P::value()</code> is a valid constant expression, then that expression shall be <code>true</code>.</li>
</ul></li>
<li>Let <code>Prop</code> be a concept-preserving property and let <code>CP</code> be a concept-enforcing property. Let <code>e</code> be a instance of a type <code>E</code> for which <code>can_require_v&lt;E, Prop&gt;</code> is <code>true</code>. Let <code>prop</code> be an instance of type <code>Prop</code>. Let <code>Props...</code> be a list of properties for which the expression <code>CP::template polymorphic_wrapper_type&lt;Props...&gt;(e)</code> is well-formed. If the expression <code>CP::template static_query_v&lt;E&gt; == CP::value()</code> is a well-formed constant expression with value <code>true</code>, the expression <code>CP::template polymorphic_wrapper_type&lt;Props...&gt;(std::require(e, prop))</code> shall be well-formed if and only if, given the type <code>T = decay_t&lt;decltype(std::require(e, prop))&gt;</code>,
<ul>
<li><code>can_query_v&lt;Pn, T&gt;</code> is <code>true</code> for all <code>Pn</code> in <code>Props...</code> where <code>Pn::polymorphic_query_result_type</code> is well-formed</li>
<li><code>can_require_concept_v&lt;Pn, T&gt;</code> is <code>true</code> for all <code>Pn</code> in <code>Props...</code> with <code>Pn::is_requirable_concept == true</code></li>
<li>for all <code>Pn</code> in <code>Props...</code> with <code>Pn::is_requirable == true</code>, either:
<ul>
<li><code>can_require_v&lt;Pn, T&gt;</code> is <code>true</code>, or</li>
<li><code>can_prefer_v&lt;Pn, T&gt;</code> is <code>true</code></li>
</ul></li>
<li><code>can_prefer_v&lt;Pn, T&gt;</code> is <code>true</code> for all <code>Pn</code> in <code>Props...</code> with <code>Pn::is_preferable == true</code></li>
</ul></li>
<li><p>[<em>Note:</em> For example, the struct <code>S</code> provides the type for a concept-enforcing property:</p></li>
</ul>
<pre class="text language-text" data-role="codeBlock" data-info="text"><code>struct S
{
  static constexpr bool is_requirable_concept = true;

  template&lt;class... Ps&gt; 
    class polymorphic_wrapper_type;

  using polymorphic_query_result_type = bool;

  template&lt;class T&gt;
    static constexpr bool static_query_v = /* ... */;

  static constexpr bool value() const { return true; }
};</code></pre>
<p><em>&#x2014;end note</em>]</p>

      </div>
      
      
    
    
    
    
    
    
    
    
  
    </body></html>