<html><head></head><body>
<h1>Constant View: A proposal for a <code>std::as_const</code> helper function template</h1>

<p>ISO/IEC JTC1 SC22 WG21 N4380 - 2015-02-06</p>

<pre><code>
ADAM David Alan Martin (adamartin@FreeBSD.org)
                       (amartin172@bloomberg.net)
Alisdair Meredith      (ameredith1@bloomberg.net)
</code></pre>

<h3>Table of Contents</h3>

<ol>
<li>Introduction</li>
<li>Background</li>
<li>Motivation</li>
<li>Alternatives</li>
<li>Discussion</li>
<li>Proposed Implementation</li>
<li>Further Discussion</li>
</ol>

<h2>Introduction</h2>

<p>This paper proposes a new helper function template <code>std::as_const</code>, which would
live in the <code>&lt;utility&gt;</code> header.  A simple example usage:</p>

<pre><code>#include &lt;utility&gt;
#include &lt;type_traits&gt;

void
demoUsage()
{
    std::string mutableString= "Hello World!";
    const std::string &amp;constView= std::as_const( mutableString );

    assert( &amp;constView == mutableString );
    assert( &amp;std::as_const( mutableString ) == mutableString );

    using WhatTypeIsIt= std::remove_reference_t&lt; decltype( std::as_const( mutableString ) &gt;;

    static_assert( std::is_same&lt; std::remove_const_t&lt; WhatTypeIsIt &gt;, std::string &gt;::value,
            "WhatTypeIsIt should be some kind of string." );
    static_assert( !std::is_same&lt; WhatTypeIsIt, std::string &gt;::value,
            "WhatTypeIsIt shouldn't be a mutable string." );
}
</code></pre>

<h2>Background</h2>

<p>The C++ Language distinguishes between 'const Type' and 'Type' in ADL lookup for
selecting function overloads.  The selection of overloads can occur among
functions like:</p>

<pre><code>int processEmployees( std::vector&lt; Employee &gt; &amp;employeeList );
bool processEmployees( const std::vector&lt; Employee &gt; &amp;employeeList );
</code></pre>

<p>Oftentimes these functions should have the same behavior, but sometimes free (or
member) functions will return different types, depending upon which qualifier
(const or non-const) applies to the source type.  For example,
<code>std::vector&lt; T &gt;::begin</code> has two overloads, one returning
<code>std::vector&lt; T &gt;::iterator</code>, and the other returning
<code>std::vector&lt; T &gt;::const_iterator</code>.  For this reason <code>cbegin</code> was added to the
container member-function manifest.</p>

<h2>Motivation</h2>

<p>A larger project often needs to call functions, like <code>processEmployees</code>,
and selecting among specific const or non-const overloads.  Further, within
C++11 and newer contexts, passing an object for binding or perfect forwarding
can often require specifying a const qualifier applies to the actual object.
This can also be useful in specifying that a template be instantiated as
adapting to a "const" reference to an object, instead of a non-const reference.</p>

<h2>Alternatives</h2>

<ol>
<li>Continue use the hard-to-use idiom <code>const_cast&lt; const T &amp; &gt;( object )</code></li>
<li>Use a more modern idiom <code>const_cast&lt; std::add_const&lt; decltype( object ) &gt;::type &amp; &gt;( object )</code></li>
<li>Provide a language extension, i.e.: <code>const_cast( object )</code> which is
equivalent to the above</li>
<li>Provide a modified cast form, i.e.: <code>(const) object</code> which is equivalent to
the above</li>
<li>Provide a new trailing cast-like form, i.e.:  <code>object const</code>, or <code>object const.blah</code>
or <code>object.blah const</code></li>
<li>Provide a library function, <code>as_const</code>, which this paper proposes</li>
</ol>

<h2>Discussion</h2>

<p>This conversion, or alternative-viewpoint, is always safe.  Following the rule
that safe and common actions shouldn't be ugly while dangerous and infrequent
actions should be hard to write, we can conclude that this addition of const is
an operation that should not be ugly and hard.  Const-cast syntax is ugly and
therefore its usage is inherently eschewed.</p>

<p>Regarding the above alternatives, each can be discussed in turn:</p>

<h3><code>const_cast&lt; const T &amp; &gt;( object )</code>:</h3>

<p>The benefits of this form are:</p>

<ul>
<li>It is portable to older compilers (e.g. C++98/03 compilers)</li>
<li>It is widely understood</li>
<li>It is not misleading</li>
</ul>

<p>The drawbacks of this form are:</p>

<ul>
<li>It is a significant amount of typing for a relatively simple operation</li>
<li>It requires the programmer to have knowledge of <code>decltype( object )</code> </li>
<li>It is phrased in a known-dangerous cast form (<code>const_cast</code>)</li>
</ul>

<h3><code>const_cast&lt; std::add_const&lt; decltype( object ) &gt;::type &amp; &gt;( object )</code>:</h3>

<p>The benefits of this form are:</p>

<ul>
<li>It is supported by C++11 and beyond</li>
<li>It requires no modifications to the C++ standard</li>
<li>It does not require the programmer to have knowledge of <code>decltype( object )</code>;
it merely requires that he use that type-deduction</li>
</ul>

<p>The drawbacks of this form are:</p>

<ul>
<li>It is not supported by C++98/03</li>
<li>It is an even more burdensome amount of typing</li>
<li>It is phrased in an incredibly ugly and hard-to-understand form</li>
<li>It is phrased using a form which requires an extra <code>typename</code> usage, when used
in a template context, due to the <code>add_const</code> metafunction</li>
<li>It is phrased in a known-dangerous cast form (<code>const_cast</code>)</li>
</ul>

<h3>Extend the language with <code>const_cast( object )</code>:</h3>

<p>The benefits of this form are:</p>

<ul>
<li>It is a simple, straightforward, and understandable construct</li>
<li>It uses a presently ill-defined form</li>
</ul>

<p>The drawbacks of this form are:</p>

<ul>
<li>It is not supported by anything, at present</li>
<li>It provides an alternate, potentially confusing difference for <code>const_cast</code>,
over the other <code>_cast</code> forms currently in the core language</li>
<li>It requires a core language extension for only marginal gain</li>
<li>It is phrased in a known-dangerous cast form, which is locatable by regex</li>
</ul>

<h3>Extend the language with <code>(const) object</code>:</h3>

<p>The benefits of this form are:</p>

<ul>
<li>It is a simple, straightforward, and understandable construct</li>
<li>It uses a presently ill-defined form</li>
<li>It is extremely terse</li>
</ul>

<p>The drawbacks of this form are:</p>

<ul>
<li>It is not supported by anything, at present</li>
<li>It requires a core language extension for only marginal gain</li>
<li>It is phrased in the legacy C-style casting form, which is considered (by
many) to be both outmoded and ugly</li>
</ul>

<h3>Library function, <code>std::as_const( object )</code>:</h3>

<p>The benefits of this form are:</p>

<ul>
<li>It is simple, straightforward, and understandable construct</li>
<li>It requires no new core language extensions</li>
<li>It is implementable in C++98/03 terms, for those who wish to back-port the
feature</li>
<li>It is terse</li>
<li>It is not misleading</li>
<li>It does not require the programmer to know <code>decltype( object )</code></li>
<li>It follows the precedent set by <code>std::move</code> and <code>std::forward</code>, in terms of
wrapping commonly needed, but difficult to write cast expressions</li>
</ul>

<p>The drawbacks of this form are:</p>

<ul>
<li>It may not have the best name.</li>
<li>Proposed names included:
<ul>
<li><code>std::constify( object )</code></li>
<li><code>std::to_const( object )</code></li>
<li><code>std::constant( object )</code></li>
<li><code>std::view_const( object )</code></li>
<li><code>std::make_const( object )</code></li>
<li><code>std::add_const( object )</code></li>
<li><code>std::const_view( object )</code></li>
</ul></li>
</ul>

<p>In proposing <code>std::as_const( object )</code>, we feel that the name is sufficiently
terse yet descriptive.  Every other name had at least one drawback.</p>

<h2>Proposed Implementation</h2>

<p>In the <code>&lt;utility&gt;</code> header, the following code should work:</p>

<pre><code>// ...
// -- Assuming that the file has reverted to the global namespace --
namespace std
{
    template&lt; typename T &gt;
    inline typename std::add_const&lt; T &gt;::type &amp;
    as_const( T &amp;t ) noexcept
    {
        return t;
    }

}
// ...
</code></pre>

<h2>Further Discussion</h2>

<p>The above implementation only supports safely re-casting an l-value as const
(even if it may have already been const).  It is probably desirable to have
xvalues and prvalues also be usable with <code>as_const</code>, but there are some issues
to consider.  Some examples of contexts we'd like to consider for an expanded
proposal are:</p>

<pre><code>std::string getString();
auto &amp;x= as_const( getString() );
auto &amp;x= const_cast&lt; const std::string &amp; &gt;( getString() );


void function( std::string &amp; );
void function( const std::string &amp; );

function( as_const( getString() ) );
</code></pre>

<p>An alternative implementation which would support all of the forms used above,
would be:</p>

<pre><code>template&lt; typename T &gt;
inline const T &amp;
as_const( const T &amp;t ) noexcept
{
    return t;
}

template&lt; typename T &gt;
inline const T
as_const( T &amp;&amp;t ) noexcept( noexcept( T( t ) ) )
{
    return t;
}
</code></pre>

<p>We believe that such an implementation helps to deal with lifetime extension
issues for temporaries which are captured by <code>as_const</code>, but we have not fully
examined all of the implications of these forms.  We are open to expanding
the scope of this proposal, but we feel that the utility of a simple-to-use
<code>as_const</code> is sufficient even without the expanded semantics.</p>
