<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
body 
{
  margin:2em;
  padding:0;
  max-width:60em;
}

blockquote
{
  margin-left:0em
}
</style></head>
    
<body><div><font size=-1>
<br><b>Doc number:</b> N4372
<br><b>Revises:</b> N4209, N4057, N3973
<br><b>Date:</b> 2015-02-06
<br><b>Project:</b> Programming Language C++, Library Evolution Working Group
<br><b>Reply-to:</b> Jonathan Coe &lt;<a href="mailto:jbcoe@me.com" target="_blank">jbcoe@me.com</a>&gt;
<br>Robert Mill &lt;<a href="mailto:rob.mill.uk@gmail.com" target="_blank">rob.mill.uk@gmail.com</a>&gt;
</font>
    
<H1>A Proposal to Add a Const-Propagating Wrapper to the Standard Library</H1>
    
<H2>I. Introduction</H2>
<p>We propose the introduction of a <tt>propagate_const</tt> wrapper class that propagates <tt>const</tt>-ness to pointer-like member variables.</p>
      
<H2>II. Motivation</H2>
<p>The behaviour of <tt>const</tt> member functions on objects with pointer-like data members is seen to be surprising by many experienced C++ developers. A <tt>const</tt> member function can call non-<tt>const</tt> functions on pointer-like data members and will do so by default without use of <tt>const_cast</tt>.</p>

<p><b>Example:</b></p>

<blockquote><tt><pre>
struct A
{
  void bar() const 
  { 
    std::cout &lt;&lt; "bar (const)" &lt;&lt; std::endl; 
  }
  
  void bar() 
  { 
    std::cout &lt;&lt; "bar (non-const)" &lt;&lt; std::endl; 
  }
};

struct B
{
  B() : m_ptrA(std::make_unique&lt;A&gt;()) {} 
  
  void foo() const 
  { 
    std::cout &lt;&lt; "foo (const)" &lt;&lt; std::endl;
    m_ptrA-&gt;bar(); 
  }           
  
  void foo() 
  { 
    std::cout &lt;&lt; "foo (non-const)" &lt;&lt; std::endl;
    m_ptrA-&gt;bar(); 
  }

  std::unique_ptr&lt;A&gt; m_ptrA;
};

int main()
{    
  B b;
  b.foo();
  
  const B const_b;
  const_b.foo();
}

</pre></tt></blockquote>

<p>Running this program gives the following output:</p>
<blockquote><tt><pre>
  foo (non-const)
  bar (non-const)
  foo (const)
  bar (non-const)
</pre></tt></blockquote>

<p>The behaviour above can be amended by re-writing <tt>void B::foo() const</tt> using <tt>const_cast</tt> to explicitly call the <tt>const</tt> member function of <tt>A</tt>. Such a change is unnatural and not common practice. We propose the introduction of a wrapper class which can be used on pointer-like member data to ensure propagation of <tt>const</tt>-ness.</p>
 
<h4>Introducing <tt>propagate_const</tt></h4>

<p>The class <tt>propagate_const</tt> is designed to function as closely as possible to a traditional pointer or smart-pointer. Pointer-like member objects can be wrapped in a <tt>propagate_const</tt> object to ensure propagation of <tt>const</tt>-ness.</p> 

<p>A <tt>const</tt>-propagating <tt>B</tt> would be written as</p>
<blockquote><tt><pre>
struct B
{
  B();              // unchanged
  
  void foo() const; // unchanged
  void foo();       // unchanged

  <font color=blue><b>std::propagate_const&lt;</b></font>std::unique_ptr&lt;A&gt;<font color=blue><b>&gt;</b></font> m_ptrA;
};
</pre></tt></blockquote>

<p>With an amended <tt>B</tt>, running the program from the earlier example will give the following output:</p> 
<blockquote><tt><pre>
  foo (non-const)
  bar (non-const)
  foo (const)
  bar (const)
</pre></tt></blockquote>   
    
<h3>The pimpl idiom with <tt>propagate_const</tt></h3>
<p>The pimpl (pointer-to-implementation) idiom pushes implementation details of a class into a separate object, a pointer to which is stored in the original class [2].</p>

<blockquote><tt><pre>class C
{
  void foo() const;
  void foo();
    
  std::unique_ptr&lt;CImpl&gt; m_pimpl;
};

void C::foo() const 
{ 
  m_pimpl-&gt;foo(); 
}

void C::foo() 
{ 
  m_pimpl-&gt;foo(); 
}

</pre></tt></blockquote> 
    
 <p>When using the pimpl idiom the compiler will not catch changes to member variables within <tt>const</tt> member functions. Member variables are kept in a separate object and the compiler only checks that the address of this object is unchanged. By introducing the pimpl idiom into a class to decouple interface and implementation, the author may have inadventantly lost compiler checks on <tt>const</tt>-correctness.</p>
    
<p>When the pimpl object is wrapped in <tt>propagate_const</tt>, <tt>const</tt> member functions will only be able to call <tt>const</tt> functions on the pimpl object and will be unable to modify (non-<tt>mutable</tt>) member variables of the pimpl object without explicit <tt>const_cast</tt>s: <tt>const</tt>-correctness is restored. The class above would be modified as follows:</p>

<blockquote><tt><pre>class C
{
  void foo() const;  // unchanged
  void foo();        // unchanged
  
  <font color=blue><b>std::propagate_const&lt;</b></font>std::unique_ptr&lt;CImpl&gt;<font color=blue><b>&gt;</b></font> m_pimpl;
};</pre></tt></blockquote> 
    
<h3>Thread-safety and <tt>propagate_const</tt></h3>

<p>Herb Sutter introduced the appealing notion that <tt>const</tt> implies thread-safe [3]. Without <tt>propagate_const</tt>, changes outside a class with pointer-like members can render the <tt>const</tt> methods of that class non-thread-safe. This means that maintaining the rule <tt>const</tt>=&gt;thread-safe requires a global review of the code base.</p>

<p>With only the <tt>const</tt> version of <tt>foo()</tt> the code below is thread-safe. Introduction of a non-<tt>const</tt> (and non-thread-safe) <tt>foo()</tt> into <tt>D</tt> renders <tt>E</tt> non-thread-safe.</p>

<blockquote><tt><pre>struct D
{
  int foo() const { /* thread-safe */ }
  int foo() { /* non-thread-safe */ }
};

struct E
{
  E(D&amp; pD) : m_pD{&amp;pD} {}

  void operator() () const
  {
    m_pD-&gt;foo();
  }

  D* m_pD;
};

int main()
{
  D d;
  const E e1(d);
  const E e2(d);

  std::thread t1(e1);
  std::thread t2(e2);
  t1.join();
  t2.join();
}
</pre></tt></blockquote>

<p>One solution to the above is to forbid pointer-like member variables in classes if <tt>const</tt>=&gt;thread-safe. This is undesirably restrictive. If instead all pointer-like member variables are decorated with <tt>propagate_const</tt> then the compiler will catch violations of <tt>const</tt>-ness that could render code non-thread-safe.</p>

<blockquote><tt><pre>struct E
{
  E(D&amp; pD);                 // unchanged

  void operator() () const; // unchanged

  <font color=blue><b>std::propagate_const&lt;</b></font>D*<font color=blue><b>&gt;</b></font> m_pD;
};</pre></tt></blockquote>

<p>Introduction of <tt>propagate_const</tt> cannot automatically guarantee thread-safety but can allow <tt>const</tt>=&gt;thread-safe to be locally verified during code review.</p>

<H2>III. Impact On the Standard</H2>

<p>This proposal is a pure library extension. It does not require changes to any standard classes, functions or headers.</p>

<H2>IV. Design Decisions</H2>

<p>Given absolute freedom we would propose changing the <tt>const</tt> keyword to propagate <tt>const</tt>-ness. That would be impractical, however, as it would break existing code and change behaviour in potentially undesirable ways. A second approach would be the introduction of a new keyword to modify <tt>const</tt>, for instance, <tt>deep const</tt>, which enforces <tt>const</tt>-propagation. Although this change would maintain backward-compatibility, it would require enhancements to the C++ compiler.</p>

<p>We suggest that the standard library supply a class that wraps member data where <tt>const</tt>-propagating behaviour is required. The <tt>propagate_const</tt> wrapper can be used much like the <tt>const</tt> keyword and will cause compilation failure wherever <tt>const</tt>-ness is violated. <tt>const</tt>-propagation can be introduced into existing code by decorating pointer-like members of a class with <tt>propagate_const</tt>.</p>
    
<p>The change required to introduce <tt>const</tt>-propagation to a class is simple and local enough to be enforced during code review and taught to C++ developers in the same way as smart-pointers are taught to ensure exception safety.</p>
    
<p>It is intended that <tt>propagate_const</tt> contain no member data besides the wrapped pointer. Inlining of function calls by the compiler will ensure that using <tt>propagate_const</tt> incurs no run-time cost.</p>

<h3>Encapsulation vs inheritance</h3>

<p>Inheritance from the wrapped pointer-like object (where it is a class type) was considered but ruled out. The purpose of this wrapper is to help the author ensure <tt>const</tt>-propagation; if <tt>propagate_const&lt;T&gt;</tt> were to inherit from <tt>T</tt>, then it would allow potentially non-<tt>const</tt> member functions of <tt>T</tt> to be called in a <tt>const</tt> context.</p>
    
<h3>Construction and assignment</h3>
<p> A <tt>propagate_const&lt;T&gt;</tt> should be move-constructable and move-assignable from a <tt>U</tt> or a <tt>propagate_const&lt;U&gt;</tt> where <tt>U</tt> is any type that <tt>T</tt> can be constructed or assigned from. 
There should be no additional cost of construction for a <tt>propagate_const&lt;T&gt;</tt> beyond that for construction of a <tt>T</tt>. 
The wrapped <tt>T</tt> should not be value-initialized as this would incur a cost for pointer types. 
If value-initialization is desirable then it can be accomplished with another wrapper class like <tt>boost::value_initialized</tt> [4].</p>

<h3>Non-copyable</h3>
<p> A <tt>propagate_const&lt;T&gt;</tt> cannot be copied or assigned from a <tt>const propagate_const&lt;T&gt;&amp;</tt>. 
This is to prevent unintentional removal of <tt>const-safety</tt> through copying. For instance:
</p>
<blockquote><tt><pre>
struct G;
struct F
{
  void const_method() const; // calls only const methods of m_g;
  
  void non_const_method(); // calls methods of m_g
  
  propagate_const&lt;G*&gt; m_g;
};

void some_function(const F&amp; f) // const-ref passed in, no resources should be accessed in a non-const manner
{
  F copy_f = f;
  f.non_const_method();
}
</blockquote></tt></pre>

<p>As <tt>propagate_const</tt> cannot be copied, the default copy and assignment operators will not be generated for <tt>F</tt>.
This will prevent the code above from compiling.
</p>


<h3>Pointer-like functions</h3>
<p><tt>operator*</tt> and <tt>operator-&gt;</tt> are defined to preserve <tt>const</tt>-propagation. When a <tt>const</tt> <tt>propagate_const&lt;T&gt;</tt> is used only <tt>const</tt> member functions of <tt>T</tt> can be used without explicit casts.</p>
    
<h3><tt>get</tt></h3>
<p>The <tt>get</tt> function returns the address of the object pointed to by the wrapped pointer. <tt>get</tt> is intended to be used to ensure <tt>const</tt>-propagation is preserved when using interfaces which require C-style pointers</p>
    
<h3><tt>operator value*</tt></h3>
<p>When <tt>T</tt> is a pointer type <tt>operator value*</tt> exists and allows implicit conversion to a pointer. This avoids using <tt>get</tt> to access the pointer in contexts where it was unnecesary before addition of the <tt>propagate_const</tt> wrapper.</p>
    
<h3>Equality, inequality and comparison</h3>    
<p>Free-standing equality, inequality and comparison operators are provided so that a <tt>propagate_const&lt;T&gt;</tt> can be used in any equality, inequality or comparison where a <tt>T</tt> could be used. <tt>const</tt>-propagation should not alter the result of any equality, inequality or comparison operation.</p>
    
<h3><tt>swap</tt></h3>    
<p><tt>swap</tt> will swap the underlying pointers.</p>
    
<h3><tt>get_underlying</tt></h3>
<p><tt>get_underlying</tt> is a free-standing function which allows the underlying pointer to be accessed. The use of this function allows <tt>const</tt>-propagation to be dropped and is therefore discouraged. The function is named such that it will be easy to find in code review.</p>
    
<h3><tt>hash</tt></h3>
<p>The <tt>hash</tt> struct is specialized so that inclusion of <tt>propagate_const</tt> does not alter the result of hash evaluation.</p>
   

<H2>V. Technical Specification</h2>
<H2>X.Y&nbsp;&nbsp;&nbsp;Class template <tt>propagate_const</tt> [propagate_const]</H2>    

<h3>X.Y.1&nbsp;&nbsp;Class template <tt>propagate_const</tt> general [propagate_const.general]</h3>
<p><tt>propagate_const</tt> is a wrapper around a pointer-like object type <tt>T</tt> which
treats the wrapped pointer as a pointer to <tt>const</tt> when
the wrapper is accessed through a <tt>const</tt> access path. 

<p><tt>T</tt> must be a pointer type or a class type for which
<tt>decltype(*declval&lt;T&amp;&gt;())</tt> is an lvalue reference; otherwise
the program is ill-formed.
If <tt>T</tt> is an array type or pointer to
function type then the program is ill-formed.  [<i>Note:</i>
propagate_const&lt;const int*&gt; is well-formed <i>-end note</i>]</p>

<h3>X.Y.2&nbsp;&nbsp;Header <tt>&lt;propagate_const&gt;</tt> synopsis [propagate_const.synopsis]</h3>
<blockquote style="margin-left:0em"><tt><pre>
namespace std {
  template &lt;class T&gt; class propagate_const { 
  public:                                                                                          
    typedef remove_reference_t&lt;decltype(*declval&lt;T&amp;&gt;())&gt; element_type;

    //<i> [propagate_const.ctor], constructors</i>
    constexpr propagate_const() = default;
    template &lt;class U&gt; 
      constexpr propagate_const(U&amp;&amp; u); 
    propagate_const(const propagate_const&amp; p) = delete;
    template &lt;class U&gt; 
      constexpr propagate_const(propagate_const&lt;U&gt;&amp;&amp; pu) noexcept(<i>see below</i>);
    
    //<i> [propagate_const.assignment], assignment</i>
    template &lt;class U&gt; 
      constexpr propagate_const&amp; operator=(U&amp;&amp; u); 
    propagate_const&amp; operator=(const propagate_const&amp; p) = delete; 
    template &lt;class U&gt; 
      constexpr propagate_const&amp; operator=(propagate_const&lt;U&gt;&amp;&amp; pu) noexcept; 
    
    //<i> [propagate_const.const_observers], const observers</i>
    explicit constexpr operator bool() const;
    constexpr const element_type* operator-&gt;() const;
    constexpr operator const element_type*() const; //<i>Not always defined</i>
    constexpr const element_type&amp; operator*() const;
    constexpr const element_type* get() const;
    
    //<i> [propagate_const.non_const_observers], non-const observers</i>
    constexpr element_type* operator-&gt;();
    constexpr operator element_type*(); //<i>Not always defined</i> 
    constexpr element_type&amp; operator*();
    constexpr element_type* get();

    //<i> [propagate_const.modifiers], modifiers</i>
    constexpr void swap(propagate_const&lt;T&gt;&amp; pt) noexcept(<i>see below</i>);
 
  private:
    T t_; //<i>exposition only</i>
  };
  
  //<i> [propagate_const.relational], relational operators</i>
  template &lt;class T&gt;
    constexpr bool operator==(const propagate_const&lt;T&gt;&amp; pt, nullptr_t);
  template &lt;class T&gt;
    constexpr bool operator==(nullptr_t, const propagate_const&lt;T&gt;&amp; pu);
  
  template &lt;class T&gt;
    constexpr bool operator!=(const propagate_const&lt;T&gt;&amp; pt, nullptr_t);
  template &lt;class T&gt;
    constexpr bool operator!=(nullptr_t, const propagate_const&lt;U&gt;&amp; pu);
  
  template &lt;class T, class U&gt;
    constexpr bool operator==(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator!=(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&lt;(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&gt;(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&lt;=(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&gt;=(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);

  template &lt;class T, class U&gt;
    constexpr bool operator==(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    constexpr bool operator!=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    constexpr bool operator&lt;(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    constexpr bool operator&gt;(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    constexpr bool operator&lt;=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    constexpr bool operator&gt;=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  
  template &lt;class T, class U&gt;
    constexpr bool operator==(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator!=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&lt;(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&gt;(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&lt;=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    constexpr bool operator&gt;=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  
  //<i> [propagate_const.algorithms], specialized algorithms</i>
  template &lt;class T&gt;
    constexpr void swap(propagate_const&lt;T&gt;&amp; pt, propagate_const&lt;T&gt;&amp; pt2) noexcept(<i>see below</i>);

  //<i> [propagate_const.underlying], underlying pointer access</i>
  template &lt;class T&gt;
    constexpr const T&amp; get_underlying(const propagate_const&lt;T&gt;&amp; pt) noexcept;
  template &lt;class T&gt;
    constexpr T&amp; get_underlying(propagate_const&lt;T&gt;&amp; pt) noexcept;
  
  //<i> [propagate_const.hash], hash support</i>
  template &lt;class T&gt;
    struct hash&lt;propagate_const&lt;T&gt;&gt;;
} // <i>end namespace std</i></pre></tt></blockquote> 


<h3>X.Y.3&nbsp;&nbsp;<tt>propagate_const</tt> constructors [propagate_const.ctor]</h3>

<div style="margin-left:20px">
<b><tt>template &lt;class U&gt; constexpr propagate_const(U&amp;&amp; u);</tt><br/></b>
<table cellpadding="6px">
  <tr><td><sup>1</sup></td><td><i>Remarks:</i> This constructor shall not participate in overload resolution unless <tt>U</tt> is implicitly convertible to <tt>T</tt>.</td></tr>
  <tr><td><sup>2</sup></td><td><i>Effects:</i> Constructs a <tt>propagate_const&lt;T&gt;</tt> that wraps a <tt>T</tt> initialized with <tt>std::forward&lt;U&gt;(u)</tt>.</td></tr>
  <tr><td><sup>3</sup></td><td><i>Post-conditions:</i> If <tt>U</tt> is a pointer type, then <tt>get()</tt> yields the value of <tt>u</tt> implicitly converted to <tt>T</tt>, otherwise <tt>get()</tt> yields the value that <tt>u.get()</tt> implicitly converted to <tt>T</tt> yielded before construction.</td></tr>
</table><p/>
<b><tt>template &lt;class U&gt; constexpr propagate_const(propagate_const&lt;U&gt;&amp;&amp; pu) noexcept(<i>see below</i>);</tt><br/></b>
<p>The constant-expression in the exception-specification is <tt>is_same&lt;T,U&gt;::value &amp;&amp; is_nothrow_move_constructable&lt;T&gt;::value</tt></p>
<table cellpadding="6px">
  <tr><td><sup>7</sup></td><td><i>Remarks:</i> This constructor shall not participate in overload resolution unless <tt>U</tt> is implicitly convertible to <tt>T</tt>.</td></tr>
  <tr><td><sup>8</sup></td><td><i>Effects:</i> Constructs a <tt>propagate_const&lt;T&gt;</tt> that wraps a <tt>T</tt> initialized with <tt>std::move(pu.t_)</tt>.</td></tr>
  <tr><td><sup>9</sup></td><td><i>Post-conditions:</i> <tt>get()</tt> yields the value that <tt>pu.get()</tt> yielded before construction.</td></tr>
</table>
</div>


<h3>X.Y.4&nbsp;&nbsp;<tt>propagate_const</tt> assignment [propagate_const.assignment]</h3>

<div style="margin-left:20px">
  <b><tt>template &lt;class U&gt; constexpr propagate_const operator=(U&amp;&amp; u);</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Remarks:</i> This function shall not participate in overload resolution unless <tt>U</tt> is implicitly convertible to <tt>T</tt>.</td></tr>
    <tr><td><sup>2</sup></td><td><i>Effects:</i> <tt>t_=forward&lt;U&gt;(u)</tt>.</td></tr>
    <tr><td><sup>3</sup></td><td><i>Returns:</i> <tt>*this</tt>.</td></tr>
  </table><p/>
  <b><tt>template &lt;class U&gt; constexpr propagate_const operator=(propagate_const&lt;U&gt;&amp;&amp; pu) noexcept(<i>see below</i>);</tt></b><br/> 
  <p>The constant-expression in the exception-specification is <tt>is_same&lt;T,U&gt;::value &amp;&amp; is_nothrow_move_assignable&lt;T&gt;::value</tt></p>
  <table cellpadding="6px">
    <tr><td><sup>7</sup></td><td><i>Remarks:</i> This function shall not participate in overload resolution unless <tt>U</tt> is implicitly convertible to <tt>T</tt>.</td></tr>
    <tr><td><sup>8</sup></td><td><i>Effects:</i> <tt>t_=std::move(pu.t_)</tt>.</td></tr>
    <tr><td><sup>9</sup></td><td><i>Returns:</i> <tt>*this</tt>.</td></tr>
  </table>
</div>


<h3>X.Y.5&nbsp;&nbsp;<tt>propagate_const</tt> const observers [propagate_const.const_observers]</h3>

<div style="margin-left:20px">
  <b><tt>explicit constexpr operator bool() const;</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Returns:</i><tt>(bool)t_</tt>.</td></tr>
  </table><p/>
  <b><tt>constexpr const element_type* operator-&gt;() const;</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>2</sup></td><td><i>Returns:</i> <tt>get()</tt>.</td></tr>
  </table><p/> 
  <b><tt>constexpr operator const element_type*() const;</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>3</sup></td><td><i>Returns:</i> <tt>get()</tt>.</td></tr>
    <tr><td><sup>4</sup></td><td><i>Remarks:</i> This function is only defined if <tt>T</tt> is a pointer type or has an implicit conversion to <tt>element_type*</tt>.</td></tr>
  </table><p/>  
  <b><tt>constexpr const element_type&amp; operator*() const;</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>5</sup></td><td><i>Requires:</i> <tt>get() != nullptr</tt>.</td></tr>
    <tr><td><sup>6</sup></td><td><i>Returns:</i> <tt>*get()</tt>.</td></tr>
    <tr><td><sup>7</sup></td><td><i>Remarks:</i> This function shall not participate in overload resolution unless <tt>element_type</tt> is not <tt>void</tt>.</td></tr>
  </table><p/>  
  <b><tt>constexpr const element_type* get() const;</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>8</sup></td><td><i>Returns:</i> <tt>t_</tt> if <tt>T</tt> is a pointer type, otherwise <tt>t_.get()</tt>.</td></tr>
  </table>  
</div>


<h3>X.Y.6&nbsp;&nbsp;<tt>propagate_const</tt> non-const observers [propagate_const.non_const_observers]</h3>

<div style="margin-left:20px">
  <b><tt>constexpr element_type* operator-&gt;();</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Returns:</i> <tt>get()</tt>.</td></tr>
  </table><p/>  
  <b><tt>constexpr operator element_type*();</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>2</sup></td><td><i>Returns:</i> <tt>get()</tt>.</td></tr>
    <tr><td><sup>3</sup></td><td><i>Remarks:</i> This function is only defined if <tt>T</tt> is a pointer type or has an implicit conversion to <tt>element_type*</tt>.</td></tr>
  </table><p/>  
  <b><tt>constexpr element_type&amp; operator*();</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>4</sup></td><td><i>Requires:</i> <tt>get() != nullptr</tt>.</td></tr>
    <tr><td><sup>5</sup></td><td><i>Returns:</i> <tt>*get()</tt>.</td></tr>
    <tr><td><sup>6</sup></td><td><i>Remarks:</i> This function shall not participate in overload resolution if <tt>element_type</tt> is <tt>void</tt>.</td></tr>
  </table><p/>
  <b><tt>constexpr element_type* get();</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>7</sup></td><td><i>Returns:</i> <tt>t_</tt> if <tt>T</tt> is a pointer type, otherwise <tt>t_.get()</tt>.</td></tr>
  </table>  
</div>


<h3>X.Y.7&nbsp;&nbsp;<tt>propagate_const</tt> modifiers [propagate_const.modifiers]</h3>

<div style="margin-left:20px">
<b><tt>constexpr void swap(propagate_const&lt;T&gt;&amp; pt) noexcept(<i>see below</i>);</tt></b><br/>
<p>The constant-expression in the exception-specification is <tt>noexcept(swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;()))</tt>.</p>
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Effects:</i> <tt>swap(t_, pt.t_)</tt>.</td></tr>
  </table>
</div>


<h3>X.Y.8&nbsp;&nbsp;<tt>propagate_const</tt> relational operators [propagate_const.relational]</h3>

<div style="margin-left:20px">
  
  <b><tt>template &lt;class T&gt;
      constexpr bool operator==(const propagate_const&lt;T&gt;&amp; pt, nullptr_t);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Returns:</i> <tt>pt.t_ == nullptr</tt>.</td></tr>
  </table>
  
  <b><tt>template &lt;class T&gt;
      constexpr bool operator==(nullptr_t, const propagate_const&lt;U&gt;&amp; pt);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>2</sup></td><td><i>Returns:</i> <tt>nullptr == pt.t_</tt>.</td></tr>
  </table>
  
  <b><tt>template &lt;class T&gt;
      constexpr bool operator!=(const propagate_const&lt;T&gt;&amp; pt, nullptr_t);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>3</sup></td><td><i>Returns:</i> <tt>pt.t_ != nullptr</tt>.</td></tr>
  </table>
  <b><tt>template &lt;class T&gt;
      constexpr bool operator!=(nullptr_t, const propagate_const&lt;T&gt;&amp; pt);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>4</sup></td><td><i>Returns:</i> <tt>nullptr != pt.t_</tt>.</td></tr>
  </table>
  <p/>
  <b><tt>template &lt;class T, class U&gt;<br/>
      &nbsp;&nbsp;constexpr bool operator==(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>5</sup></td><td><i>Returns:</i> <tt>pt.t_ == pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;<br/>
     &nbsp;&nbsp;constexpr bool operator!=(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>6</sup></td><td><i>Returns:</i> <tt>pt.t_ != pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;<br/> 
      &nbsp;&nbsp;constexpr bool operator&lt;(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>7</sup></td><td><i>Returns:</i> <tt>pt.t_ &lt; pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;<br/>
      &nbsp;&nbsp;constexpr bool operator&gt;(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>8</sup></td><td><i>Returns:</i> <tt>pt.t_ &gt; pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;<br/>
      &nbsp;&nbsp;constexpr bool operator&lt;=(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>9</sup></td><td><i>Returns:</i> <tt>pt.t_ &lt;= pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;<br/>
      &nbsp;&nbsp;constexpr bool operator&gt;=(const propagate_const&lt;T&gt;&amp; pt, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>10</sup></td><td><i>Returns:</i> <tt>pt.t_ &gt;= pu.t_</tt>.</td></tr>
  </table>
  <p/>
  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator==(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>11</sup></td><td><i>Returns:</i> <tt>pt.t_ == u</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator!=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>12</sup></td><td><i>Returns:</i> <tt>pt.t_ != u</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&lt;(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>13</sup></td><td><i>Returns:</i> <tt>pt.t_ &lt; u</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&gt;(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>14</sup></td><td><i>Returns:</i> <tt>pt.t_ &gt; u</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&lt;=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>15</sup></td><td><i>Returns:</i> <tt>pt.t_ &lt;= u</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&gt;=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>16</sup></td><td><i>Returns:</i> <tt>pt.t_ &gt;= u</tt>.</td></tr>
  </table>
  <p/>
  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator==(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>17</sup></td><td><i>Returns:</i> <tt>t == pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator!=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>18</sup></td><td><i>Returns:</i> <tt>t != pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&lt;(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>19</sup></td><td><i>Returns:</i> <tt>t &lt; pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&gt;(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>20</sup></td><td><i>Returns:</i> <tt>t &gt; pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&lt;=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>21</sup></td><td><i>Returns:</i> <tt>t &lt;= pu.t_</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      constexpr bool operator&gt;=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>22</sup></td><td><i>Returns:</i> <tt>t &gt;= pu.t_</tt>.</td></tr>
  </table>
</div>


<h3>X.Y.9&nbsp;&nbsp;<tt>propagate_const</tt> specialized algorithms [propagate_const.algorithms]</h3>

<div style="margin-left:20px">
  <b><tt>template &lt;class T&gt; constexpr void swap(propagate_const&lt;T&gt;&amp; pt1, propagate_const&lt;T&gt;&amp; pt2) noexcept(<i>see below</i>);</tt></b><br/>
  <p>The constant-expression in the exception-specification is <tt>noexcept(swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;()))</tt>.</p>
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Effects:</i> <tt>swap(pt1.t_, pt2.t_)</tt>.</td></tr>
  </table>
</div>


<h3>X.Y.10&nbsp;&nbsp;<tt>propagate_const</tt> underlying pointer access [propagate_const.underlying]</h3>
<p style="margin-left:20px">Access to the underlying pointer type is through free functions rather than member functions. These functions are intended to resemble cast operations to encourage caution when using them.</p> 
<div style="margin-left:20px">
  <b><tt>template &lt;class T&gt; constexpr const T&amp; get_underlying(const propagate_const&lt;T&gt;&amp; pt) noexcept;</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Returns:</i> a reference to the underlying pointer type.</td></tr>
  </table>
  <b><tt>template &lt;class T&gt; constexpr T&amp; get_underlying(propagate_const&lt;T&gt;&amp; pt) noexcept;</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>2</sup></td><td><i>Returns:</i> a reference to the underlying pointer type.</td></tr>
  </table>
</div>


<h3>X.Y.11&nbsp;&nbsp;<tt>propagate_const</tt> hash support [propagate_const.hash]</h3>
<div style="margin-left:20px">
  <b><tt>template &lt;class T&gt; struct hash&lt;propagate_const&lt;T&gt;&gt;;</tt></b><br/>
  <div>
    <p style="margin-left:20px">The template specialization shall meet the requirements of class template <tt>hash</tt> (20.9.12).</p> 
    <p style="margin-left:20px">For an object <tt>p</tt> of type <tt>propagate_const&lt;T&gt;</tt>, <tt>hash&lt;propagate_const&lt;T&gt;()(p)</tt>
    shall evaluate to the same value as <tt>hash&lt;T&gt;()(p.t_)</tt>.</p>
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Requires:</i> The specialization <tt>hash&lt;T&gt;</tt> shall be well-formed and well-defined, 
        and shall meet the requirements of class template hash.</td></tr>
  </table>
  </div>
</div>


<H2>VI. Acknowledgements</H2>
<p>Thanks to Walter Brown, Kevin Channon, Stephan T. Lavavej, Nick Maclaren, Roger Orr, Ville Voutilainen, Jonathan Wakely, David Ward, the staff of the Creative Assembly and others for helpful discussion.</p>

<H2>VII. Revisions</H2>
<p>This paper revises N4209</p>
<ul>
  <li>Default constructor is now defaulted.</li>
  <li>Added <tt>constexpr</tt>.</li>
  <li>Added <tt>noexcept</tt>.</li>
  <li>Altered relational operators, assignement and swap to use <tt>t_</tt>.</li>
  <li>Copy and assignment from const reference are now deleted.</li>
  <li>delete function provided when <tt>T</tt> is a pointer.</li>
</ul>

<p>N4209 revises N4057</p>
<ul>
  <li>Extended comparison operators to avoid reliance on implicit conversions.</li>
  <li>Minor cosmetic changes.</li>
</ul>
    
<p>N4057 revises N3973</p>
<ul>
<li>Renamed class from <tt>logical_const</tt> to <tt>propagate_const</tt> as the former is used with different meaning in the D community.</li> 
<li>Add <tt>enable_if</tt> to reference implementation to prevent some functions entering into an overload set.</li>
</ul>
    
<H2>VIII. References</H2>
<ul>
  <li>[1] Bjarne Stroustrup, The C++ Programming Language, 4th edition, 2013,
          Addison Wesley ISBN-10: 0321563840 p464</li>

  <li>[2] Martin Reddy, API design for C++, 2011, Elsevier ISBN-10: 0123850037, Section 3.1</li>

    <li>[3]
        <a href="http://channel9.msdn.com/posts/C-and-Beyond-2012-Herb-Sutter-You-dont-know-blank-and-blank">Herb Sutter, C++ and Beyond 2012: Herb Sutter - You don't know [blank] and [blank]</a></li>
    <li>[4]
        <a href="http://www.boost.org/doc/libs/1_55_0/libs/utility/value_init.htm">boost value_initialized</a></li>
</ul>

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