<html>

<head>
<title>Adopt Type Traits Variable Templates from Library Fundamentals TS for C++17</title>
<style type="text/css">
  p {text-align:justify}
  li {text-align:justify}
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
</style>
</head>

<body>
<table>
<tr>
  <td align="left">Doc. no.</td>
  <td align="left">P0006R0</td>
</tr>
<tr>
  <td align="left">Date:</td>
  <td align="left">2015-09-28</td>
</tr>
<tr>
  <td align="left">Project:</td>
  <td align="left">Programming Language C++</td>
</tr>
<tr>
  <td align="left">Reply to:</td>
  <td align="left">Alisdair Meredith &lt;<a href="mailto:ameredith1@bloomberg.net">ameredith1@bloomberg.net</a>&gt;</td>
</tr>
</table>

<h1>Adopt Type Traits Variable Templates from Library Fundamentals TS for C++17</tt></h1>

<h2>Table of Contents</h2>
<ul>
<li><a href="#1.0">Introduction</a></li>
<li><a href="#2.0">Recommended for Immediate Adoption</a></li>
<li><a href="#3.0">Proposed Wording</a></li>
<li><a href="#4.0">Acknowledgements</a></li>
<li><a href="#5.0">References</a></li>
</ul>


<h2><a name="1.0">Introduction</a></h2>
<p>
This paper recommends adopting the Type Trait Variable Templates from the
Library Fundamentals TS for C++17.  It does <em>not</em> propose removing
them from the Library Fundamentals 2 TS, as parts of the TS rely on their
presence, which is not available in the C++14 standard that is the base
document for that series of TS.
</p>


<h2><a name="2.0">Recommended for Immediate Adoption</a></h2>
<p>
Following the success of the <tt>_t</tt> alias templates for type traits,
a matching set of <tt>_v</tt> variable templates have been proposed.  The
language support for variable templates arrived too late to confidently
make this change for C++14, but experience since has shown that such variable
templates are more succinct, can clean up the text in a similar way that
the <tt>_t</tt> aliases have been widely adopted through the standard, and
the author's experience using them in his own implementation of the standard
type traits library is that code is much simpler when written using such
variable templates directly, rather than turning a value into a type, then
performing template manipulations on the type, before turning the type back
into a value.
</p>
<p>
The impact on the standard is that many places that reference
<tt>some_trait&lt;T&gt;::value</tt> would instead use <tt>some_trait_v&lt;T&gt;</tt>.
The saving is not quite as great as in the case of alias templates, as there
is no irksome <tt>typename</tt> to remove.  However, the consistecy of using
<tt>_t</tt> and <tt>_v</tt> to refer to traits, and not using <tt>::<i>something</i></tt>
to extract meaning is compelling.
</p>
<p>
This paper proposes adding all of the <tt>_v</tt> alias templates from the
Library Fundamentals working paper into the C++ Standard working paper, along
with giving editorial direction to consistently use <tt>_v</tt> notation in
wording throughout the standard.  The paper author volunteers to help the editors
with such a project.  Adopting this feature now gives more time for the editors
to catch any stray usage, before sending out the CD for ballot, hopefully next
year.
</p>
<p>
It is important to bring this feature forward for adoption, even ahead of other
Library Fundamentals components, as it has not only proven itself quickly, but
the design is non-controversial, and the impact on how we document the standard
library is significant.  If we want to have a consistent use of the <tt>_v</tt>
variables, rather than the more verbose <tt>::value</tt> traits throughout the
standard, then we need to adopt this langauge as soon as possible, in order to
perform the subsequent editorial cleanup in a reasonable timeframe, and so that
new proposals can be written using the (expected) preferred language.
</p>

<h2><a name="3.0">Proposed Wording</a></h2>
<p>
</p>

<p>
Add to the <tt>&lt;system_error&gt;</tt> synopsis, <b>19.5p2 [syserr]</b>:
</p>

<pre>
  // 19.5, System error support
  template &lt;class T&gt; constexpr bool is_error_code_enum_v
    = is_error_code_enum&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_error_condition_enum_v
    = is_error_condition_enum&lt;T&gt;::value;
</pre>


<p>
Add to the <tt>&lt;tuple&gt;</tt> synopsis, <b>20.4.1p2 [tuple.general]</b>:
</p>

<pre>
  // 20.4.2.5, tuple helper classes
  template &lt;class T&gt; constexpr size_t tuple_size_v
    = tuple_size&lt;T&gt;::value;
</pre>


<p>
Add to the <tt>&lt;memory&gt;</tt> synopsis, <b>20.7.2p1 [memory.syn]</b>:
</p>

<pre>
  // 20.7.7, uses_allocator
  template &lt;class T, class Alloc&gt; constexpr bool uses_allocator_v
    = uses_allocator&lt;T, Alloc&gt;::value;
</pre>


<p>
Add to the <tt>&lt;functional&gt;</tt> synopsis, <b>20.9p2 [function.objects]</b>:
</p>

<pre>
    // 20.9.9, Function object binders
    template &lt;class T&gt; constexpr bool is_bind_expression_v
      = is_bind_expression&lt;T&gt;::value;
    template &lt;class T&gt; constexpr int is_placeholder_v
      = is_placeholder&lt;T&gt;::value;
</pre>


<p>
Add to the <tt>&lt;type_traits&gt;</tt> synopsis, <b>20.10.2 [meta.type.synop]</b>:
</p>

<pre>
  // 20.10.4.1, primary type categories
  template &lt;class T&gt; constexpr bool is_void_v
    = is_void&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_null_pointer_v
    = is_null_pointer&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_integral_v
    = is_integral&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_floating_point_v
    = is_floating_point&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_array_v
    = is_array&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_pointer_v
    = is_pointer&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_lvalue_reference_v
    = is_lvalue_reference&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_rvalue_reference_v
    = is_rvalue_reference&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_member_object_pointer_v
    = is_member_object_pointer&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_member_function_pointer_v
    = is_member_function_pointer&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_enum_v
    = is_enum&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_union_v
    = is_union&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_class_v
    = is_class&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_function_v
    = is_function&lt;T&gt;::value;

  // 20.10.4.2, composite type categories
  template &lt;class T&gt; constexpr bool is_reference_v
    = is_reference&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_arithmetic_v
    = is_arithmetic&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_fundamental_v
    = is_fundamental&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_object_v
    = is_object&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_scalar_v
    = is_scalar&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_compound_v
    = is_compound&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_member_pointer_v
    = is_member_pointer&lt;T&gt;::value;

  // 20.10.4.3, type properties
  template &lt;class T&gt; constexpr bool is_const_v
    = is_const&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_volatile_v
    = is_volatile&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivial_v
    = is_trivial&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivially_copyable_v
    = is_trivially_copyable&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_standard_layout_v
    = is_standard_layout&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_pod_v
    = is_pod&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_literal_type_v
    = is_literal_type&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_empty_v
    = is_empty&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_polymorphic_v
    = is_polymorphic&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_abstract_v
    = is_abstract&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_final_v
    = is_final&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_signed_v
    = is_signed&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_unsigned_v
    = is_unsigned&lt;T&gt;::value;
  template &lt;class T, class... Args&gt; constexpr bool is_constructible_v
    = is_constructible&lt;T, Args...&gt;::value;
  template &lt;class T&gt; constexpr bool is_default_constructible_v
    = is_default_constructible&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_copy_constructible_v
    = is_copy_constructible&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_move_constructible_v
    = is_move_constructible&lt;T&gt;::value;
  template &lt;class T, class U&gt; constexpr bool is_assignable_v
    = is_assignable&lt;T, U&gt;::value;
  template &lt;class T&gt; constexpr bool is_copy_assignable_v
    = is_copy_assignable&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_move_assignable_v
    = is_move_assignable&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_destructible_v
    = is_destructible&lt;T&gt;::value;
  template &lt;class T, class... Args&gt; constexpr bool is_trivially_constructible_v
    = is_trivially_constructible&lt;T, Args...&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivially_default_constructible_v
    = is_trivially_default_constructible&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivially_copy_constructible_v
    = is_trivially_copy_constructible&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivially_move_constructible_v
    = is_trivially_move_constructible&lt;T&gt;::value;
  template &lt;class T, class U&gt; constexpr bool is_trivially_assignable_v
    = is_trivially_assignable&lt;T, U&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivially_copy_assignable_v
    = is_trivially_copy_assignable&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivially_move_assignable_v
    = is_trivially_move_assignable&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_trivially_destructible_v
    = is_trivially_destructible&lt;T&gt;::value;
  template &lt;class T, class... Args&gt; constexpr bool is_nothrow_constructible_v
    = is_nothrow_constructible&lt;T, Args...&gt;::value;
  template &lt;class T&gt; constexpr bool is_nothrow_default_constructible_v
    = is_nothrow_default_constructible&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_nothrow_copy_constructible_v
    = is_nothrow_copy_constructible&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_nothrow_move_constructible_v
    = is_nothrow_move_constructible&lt;T&gt;::value;
  template &lt;class T, class U&gt; constexpr bool is_nothrow_assignable_v
    = is_nothrow_assignable&lt;T, U&gt;::value;
  template &lt;class T&gt; constexpr bool is_nothrow_copy_assignable_v
    = is_nothrow_copy_assignable&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_nothrow_move_assignable_v
    = is_nothrow_move_assignable&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool is_nothrow_destructible_v
    = is_nothrow_destructible&lt;T&gt;::value;
  template &lt;class T&gt; constexpr bool has_virtual_destructor_v
    = has_virtual_destructor&lt;T&gt;::value;

  // See 20.10.5, type property queries
  template &lt;class T&gt; constexpr size_t alignment_of_v
    = alignment_of&lt;T&gt;::value;
  template &lt;class T&gt; constexpr size_t rank_v
    = rank&lt;T&gt;::value;
  template &lt;class T, unsigned I = 0&gt; constexpr size_t extent_v
    = extent&lt;T, I&gt;::value;

  // See 20.10.6, type relations
  template &lt;class T, class U&gt; constexpr bool is_same_v
    = is_same&lt;T, U&gt;::value;
  template &lt;class Base, class Derived&gt; constexpr bool is_base_of_v
    = is_base_of&lt;Base, Derived&gt;::value;
  template &lt;class From, class To&gt; constexpr bool is_convertible_v
    = is_convertible&lt;From, To&gt;::value;
</pre>


<p>
Add to the <tt>&lt;ratio&gt;</tt> synopsis, <b>20.11.2 [ratio.syn]</b>:
</p>

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


<p>
Add to the <tt>&lt;chrono&gt;</tt> synopsis, <b>20.12.2 [time.syn]</b>:
</p>

<pre>
  // 20.12.4, customization traits
  template &lt;class Rep&gt; constexpr bool treat_as_floating_point_v
    = treat_as_floating_point&lt;Rep&gt;::value;
</pre>


<h2><a name="4.0">Acknowledgements</a></h2>
<p>
Thanks to Walter Brown for proposing and persevering with the variable
template language feature for C++14, and to Stephan T. Lavavej for
proposing their idiomatic use in the type traits library, and beyond.
</p>


<h2><a name="5.0">References</h2>
<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3932">N3932</a> Variable Templates For Type Traits, Stephan T. Lavavej
</p>
<p>
<a href=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480">N4480</a> Library Fundamentals TS (Final Draft)
</p>

</body>
</html>
