<!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;
}
</style></head>

<body style="max-width:60em;">
    
<body><div><font size=-1>
<br><b>Doc number:</b> N4209
<br><b>Revises:</b> N4057, N3973
<br><b>Date:</b> 2014-10-9
<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 constructable and 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 raw pointers. If value-initialization is desirable then it can be accomplished with another wrapper class like <tt>boost::value_initialized</tt> [4].</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 raw C-style pointers</p>
    
<h3><tt>operator value*</tt></h3>
<p>When <tt>T</tt> is a raw pointer <tt>operator value*</tt> exists and allows implicit conversion to a raw pointer. This avoids using <tt>get</tt> to access the raw 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>Neither the member <tt>swap</tt> function nor the free-standing <tt>swap</tt> function should add or remove <tt>const</tt>-ness but should not unduly restrict the types with which <tt>propagate_const&lt;T&gt;</tt> can be swapped. If <tt>T</tt> and <tt>U</tt> can be swapped then <tt>const</tt>-propagating <tt>T</tt> and <tt>U</tt> can be swapped.</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>The header <tt>&lt;propagate_const&gt;</tt> defines a template class 
<tt>propagate_const</tt> that imposes deep-const behaviour on pointer types.</p>

<h3>X.Y.2&nbsp;&nbsp;Class template <tt>propagate_const</tt> overview [propagate_const.overview]</h3>
<p><tt>propagate_const</tt> is a wrapper around a pointer type <tt>T</tt> which
treats the wrapped pointer as a <tt>const</tt> pointer to <tt>const</tt> when
the wrapper is accessed as a <tt>const</tt> object. 

<h3>X.Y.3&nbsp;&nbsp;Class template <tt>propagate_const</tt> requirements on <tt>T</tt> [propagate_const.requirements]</h3>

<tr><tt>T</tt> is required to be a raw pointer to an object or a class type
imitating a pointer to an object; anything else is ill-formed.
<tt>decltype(*declval&lt;T&amp;&gt;())</tt> must be well-formed and must return
an lvalue reference; anything else is ill-formed. If <tt>T</tt> is a pointer to
const then <tt>propagate_const</tt> remains well-formed.

<h3>X.Y.4&nbsp;&nbsp;Class template <tt>propagate_const noexcept</tt> status [propagate_const.noexcept]</h3>
<p>When <tt>T</tt> is a raw pointer then all member functions of <tt>propagate_const</tt>
are <tt>noexcept</tt>. When <tt>T</tt> is a class type imitating a pointer then member functions
of <tt>propagate_const</tt> may be conditionally <tt>noexcept</tt>.</p>

<h3>X.Y.5&nbsp;&nbsp;Header <tt>&lt;propagate_const&gt;</tt> synopsis [propagate_const.synopsis]</h3>
<blockquote><tt><pre>
namespace std {
  template &lt;class T&gt; class propagate_const { 
  public:                                                                                          
    typedef decltype(*declval&lt;T&amp;&gt;()) element_type;
    typedef element_type* pointer_type;
       
    //<i> Constructors</i>
    constexpr propagate_const();
    template &lt;class U&gt; 
      propagate_const(U&amp;&amp; u); 
    template &lt;class U&gt; 
      propagate_const(const propagate_const&lt;U&gt;&amp; pu);
    template &lt;class U&gt; 
      propagate_const(propagate_const&lt;U&gt;&amp;&amp; pu);
    
    //<i> Destructor</i>
    ~propagate_const() = default;
    
    //<i> Assignment</i>
    template &lt;class U&gt; 
      propagate_const operator=(U&amp;&amp; u); 
    template &lt;class U&gt; 
      propagate_const operator=(const propagate_const&lt;U&gt;&amp; pu); 
    template &lt;class U&gt; 
      propagate_const operator=(propagate_const&lt;U&gt;&amp;&amp; pu); 
    
    //<i> Observers</i>
    explicit operator bool() const;
    const element_type* operator-&gt;() const;
    operator const element_type*() const; 
    const element_type&amp; operator*() const;
    const element_type* get() const;
    
    //<i> Accessors</i>
    element_type* operator-&gt;();
    operator element_type*(); 
    element_type&amp; operator*();
    element_type* get();

    //<i> Modifiers</i>
    void swap(propagate_const&lt;T&gt;&amp; pt);
 
  private:
    T t_; //<i>exposition only</i>
  };
  
  //<i> Relational operators</i>
  template &lt;class T, class U&gt;
    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;
    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;
    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;
    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;
    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;
    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;
    bool operator==(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    bool operator!=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    bool operator&lt;(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    bool operator&gt;(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    bool operator&lt;=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  template &lt;class T, class U&gt;
    bool operator&gt;=(const propagate_const&lt;T&gt;&amp; pt, const U&amp; u);
  
  template &lt;class T, class U&gt;
    bool operator==(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    bool operator!=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    bool operator&lt;(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    bool operator&gt;(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    bool operator&lt;=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  template &lt;class T, class U&gt;
    bool operator&gt;=(const T&amp; t, const propagate_const&lt;U&gt;&amp; pu);
  
  //<i> Specialized algorithms</i>
  template &lt;class T&gt;
    void swap (propagate_const&lt;T&gt;&amp; pt, propagate_const&lt;T&gt;&amp; pt2);
  
  //<i> Underlying pointer access</i>
  template &lt;class T&gt;
    const T&amp; get_underlying(const propagate_const&lt;T&gt;&amp; pt);
  template &lt;class T&gt;
    T&amp; get_underlying(propagate_const&lt;T&gt;&amp; pt);
  
  //<i> Hash support</i>
  template &lt;class T&gt;
    struct hash&lt;propagate_const&lt;T&gt;&gt;;
}</pre></tt></blockquote> 


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

<div style="margin-left:20px">
<b><tt>propagate_const();</tt><br/></b>
<table cellpadding="6px">
  <tr><td><sup>1</sup></td><td><i>Effects:</i> Constructs a <tt>propagate_const&lt;T&gt;</tt> that wraps a default-initialized <tt>T</tt>.</td></tr>
</table>
<b><tt>template &lt;class U&gt; propagate_const(U&amp;&amp; u);</tt><br/></b>
<table cellpadding="6px">
  <tr><td><sup>2</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>3</sup></td><td><i>Effects:</i> Constructs a <tt>propagate_const&lt;T&gt;</tt> that wraps a <tt>T</tt>. If <tt>U</tt> is an rvalue reference, then the wrapped <tt>T</tt> is move constructed from <tt>u</tt>, otherwise the wrapped <tt>T</tt> is copy constructed from <tt>u</tt>.</td></tr>
  <tr><td><sup>4</sup></td><td><i>Post-conditions:</i> If <tt>u</tt> is a raw pointer, then <tt>get()</tt> yields <tt>u</tt>, otherwise <tt>get()</tt> yields the value that <tt>u.get()</tt> yielded before construction.</td></tr>
</table>
<b><tt>template &lt;class U&gt; propagate_const(const propagate_const&lt;U&gt;&amp; pu);</tt><br/></b>
<table cellpadding="6px">
  <tr><td><sup>5</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>6</sup></td><td><i>Effects:</i> Constructs a <tt>propagate_const&lt;T&gt;</tt> that wraps a <tt>T</tt> constructed from the  pointer type wrapped by <tt>pu</tt>.</td></tr>
  <tr><td><sup>7</sup></td><td><i>Post-conditions:</i> <tt>get()</tt> yields the value that <tt>pu.get()</tt> yielded before construction.</td></tr>
</table>
<b><tt>template &lt;class U&gt; propagate_const(propagate_const&lt;U&gt;&amp;&amp; pu);</tt><br/></b>
<table cellpadding="6px">
  <tr><td><sup>8</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>9</sup></td><td><i>Effects:</i> Constructs a <tt>propagate_const&lt;T&gt;</tt> that wraps an rvalue constructed <tt>T</tt> from the pointer type wrapped by <tt>pu</tt>.</td></tr>
  <tr><td><sup>10</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.7&nbsp;&nbsp;<tt>propagate_const</tt> destructor [propagate_const.dtor]</h3>

<div style="margin-left:20px">
<b><tt>~propagate_const();</tt></b><br/>
<table cellpadding="6px">
  <tr><td><sup>1</sup></td><td><i>Effects:</i> Destroys the wrapped object.</td></tr>
</table>
</div>


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

<div style="margin-left:20px">
  <b><tt>template &lt;class U&gt; 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> The wrapped pointer type is assigned to <tt>forward&lt;U&gt;(u)</tt>.</td></tr>
    <tr><td><sup>3</sup></td><td><i>Returns:</i> <tt>*this</tt>.</td></tr>
  </table>
  <b><tt>template &lt;class U&gt; propagate_const operator=(const propagate_const&lt;U&gt;&amp; pu);</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>4</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>5</sup></td><td><i>Effects:</i> The wrapped pointer type is assigned to the wrapped pointer in <tt>pu</tt>.</td></tr>
    <tr><td><sup>6</sup></td><td><i>Returns:</i> <tt>*this</tt>.</td></tr>
  </table>
  <b><tt>template &lt;class U&gt; propagate_const operator=(propagate_const&lt;U&gt;&amp;&amp; pu);</tt></b><br/> 
  <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> The wrapped pointer type is move-assigned to the wrapped pointer in <tt>pu</tt>.</td></tr>
    <tr><td><sup>9</sup></td><td><i>Returns:</i> <tt>*this</tt>.</td></tr>
  </table>
</div>


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

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


<h3>X.Y.10&nbsp;&nbsp;<tt>propagate_const</tt> accessors [propagate_const.accessors]</h3>

<div style="margin-left:20px">
  <b><tt>element_type* operator-&gt;();</tt></b><br/> 
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Requires:</i> <tt>get() != nullptr</tt>.</td></tr>
    <tr><td><sup>2</sup></td><td><i>Returns:</i> <tt>get()</tt>.</td></tr>
  </table>  
  <b><tt>operator element_type*();</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 shall participate in overload resolution only if <tt>T</tt> is a raw pointer or has an implicit conversion to <tt>element_type*</tt>.</td></tr>
  </table>  
  <b><tt>element_type&amp; operator*();</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 if <tt>element_type</tt> is <tt>void</tt>.</td></tr>
  </table>
  <b><tt>element_type* get();</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 raw pointer, otherwise <tt>t_.get()</tt>.</td></tr>
  </table>  
</div>


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

<div style="margin-left:20px">
<b><tt>void swap(propagate_const&amp;&lt;T&gt; pt);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Effects:</i> Swaps the wrapped pointer type of <tt>*this</tt> with the wrapped pointer type of <tt>pt</tt>.</td></tr>
  </table>
</div>


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

<div style="margin-left:20px">
  
  <b><tt>template &lt;class T, class U&gt;
      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>1</sup></td><td><i>Returns:</i> <tt>pt.get() == pu.get()</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;
      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>2</sup></td><td><i>Returns:</i> <tt>pt.get() != pu.get()</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;
      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>3</sup></td><td><i>Returns:</i> <tt>pt.get() &lt; pu.get()</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;
      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>4</sup></td><td><i>Returns:</i> <tt>pt.get() &gt; pu.get()</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;
      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>5</sup></td><td><i>Returns:</i> <tt>pt.get() &lt;= pu.get()</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt;
      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>6</sup></td><td><i>Returns:</i> <tt>pt.get() &gt;= pu.get()</tt>.</td></tr>
  </table><br/>

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

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

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

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

  <b><tt>template &lt;class T, class U&gt; 
      bool operator&lt;=(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.get() &lt;= u</tt>.</td></tr>
  </table>

  <b><tt>template &lt;class T, class U&gt; 
      bool operator&gt;=(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.get() &gt;= u</tt>.</td></tr>
  </table><br/>

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

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

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

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

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

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


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

<div style="margin-left:20px">
  <b><tt>template &lt;class T&gt; void swap(propagate_const&lt;T&gt;&amp; pt1, propagate_const&lt;T&gt;&amp; pt2);</tt></b><br/>
  <table cellpadding="6px">
    <tr><td><sup>1</sup></td><td><i>Effects:</i> Calls <tt>pt1.swap(pt2)</tt>.</td></tr>
  </table>
</div>


<h3>X.Y.14&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; const T&amp; get_underlying(const propagate_const&lt;T&gt;&amp; pt);</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; T&amp; get_underlying(propagate_const&lt;T&gt;&amp; pt);</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.15&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 hash (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<PC>()(p)</tt>
    shall evaluate to the same value as <tt>hash<T>()(p.get())</tt>.</p>
    <p style="margin-left:20px"><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.</p>
    </div>
  </div>
</div>


<H2>VI. Acknowledgements</H2>
<p>Thanks to Walter Brown, Kevin Channon, Nick Maclaren, Roger Orr, Ville Voutilainen, Jonathan Wakely, David Ward and others for helpful discussion.</p>

<H2>VII. Revisions</H2>
<p>This paper revises N4057</p>
<ul>
<li>Extended comparison operators to avoid reliance on implicit conversions. 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>IX. 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>
