Doc. no. | P0007R1 |
Date: | 2015-10-22 |
Project: | Programming Language C++ |
Reply to: | ADAM David Alan Martin (<adamartin@FreeBSD.org>) |
Alisdair Meredith (<ameredith1@bloomberg.net>) |
std::as_const
helper function templateAdded proposed wording for the standard.
This paper was presented to LEWG at the Lenexa meeting in May 2015, and greeted favorably. It was held back from moving to LWG only for the lack of proposed wording, added in this update.
const_cast< const T & >( object )
const_cast< std::add_const< decltype( object ) >::type & >( object )
const_cast( object )
(const) object
std::as_const( object )
This paper proposes a new helper function template std::as_const
, which would
live in the <utility>
header. A simple example usage:
#include <utility>
#include <type_traits>
void
demoUsage()
{
std::string mutableString= "Hello World!";
const std::string &constView= std::as_const( mutableString );
assert( &constView == mutableString );
assert( &std::as_const( mutableString ) == mutableString );
using WhatTypeIsIt= std::remove_reference_t< decltype( std::as_const( mutableString ) >;
static_assert( std::is_same< std::remove_const_t< WhatTypeIsIt >, std::string >::value,
"WhatTypeIsIt should be some kind of string." );
static_assert( !std::is_same< WhatTypeIsIt, std::string >::value,
"WhatTypeIsIt shouldn't be a mutable string." );
}
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:
int processEmployees( std::vector< Employee > &employeeList );
bool processEmployees( const std::vector< Employee > &employeeList );
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,
std::vector< T >::begin
has two overloads, one returning
std::vector< T >::iterator
, and the other returning
std::vector< T >::const_iterator
. For this reason cbegin
was added to the
container member-function manifest.
A larger project often needs to call functions, like processEmployees
,
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.
const_cast< const T & >( object )
const_cast< std::add_const< decltype( object ) >::type & >( object )
const_cast( object )
which is
equivalent to the above(const) object
which is equivalent to
the aboveobject const
, or object const.blah
or object.blah const
as_const
, which this paper proposesThis 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.
Regarding the above alternatives, each can be discussed in turn:
const_cast< const T & >( object )
:The benefits of this form are:
The drawbacks of this form are:
decltype( object )
const_cast
)const_cast< std::add_const< decltype( object ) >::type & >( object )
:The benefits of this form are:
decltype( object )
;
it merely requires that he use that type-deductionThe drawbacks of this form are:
typename
usage, when used
in a template context, due to the add_const
metafunctionconst_cast
)const_cast( object )
:The benefits of this form are:
The drawbacks of this form are:
const_cast
,
over the other _cast
forms currently in the core language(const) object
:The benefits of this form are:
The drawbacks of this form are:
std::as_const( object )
:The benefits of this form are:
decltype( object )
std::move
and std::forward
, in terms of
wrapping commonly needed, but difficult to write cast expressionsThe drawbacks of this form are:
std::constify( object )
std::to_const( object )
std::constant( object )
std::view_const( object )
std::make_const( object )
std::add_const( object )
std::const_view( object )
In proposing std::as_const( object )
, we feel that the name is sufficiently
terse yet descriptive. Every other name had at least one drawback.
In the <utility>
header, the following code should work:
// ...
// -- Assuming that the file has reverted to the global namespace --
namespace std
{
template< typename T >
inline typename std::add_const< T >::type &
as_const( T &t ) noexcept
{
return t;
}
}
// ...
Insert the following signature into the <utility> synopsis, between 20.2.4 // forward/move, and 20.2.5 // declval:
template <class T> constexpr add_const_t<T>& as_const(T& t) noexcept; template <class T> void as_const(const T&&) = delete;
Insert the following subclause between 20.2.4 forward/move helpers [forward], and 20.2.5 Function template declval [declval]:
template <class T> constexpr add_const_t<T>& as_const(T& t) noexcept;
1 Returns: t.
For the purposes of SD-6, we recommend the feature detection macro __cpp_lib_as_const_function.