forked from Alepha/Alepha
Constness.
This commit is contained in:
@ -33,6 +33,7 @@ add_subdirectory( string_algorithms.test )
|
||||
add_subdirectory( tuplize_args.test )
|
||||
add_subdirectory( Thread.test )
|
||||
add_subdirectory( assertion.test )
|
||||
add_subdirectory( Constness.test )
|
||||
|
||||
# Sample applications
|
||||
add_executable( example example.cc )
|
||||
|
152
Constness.h
Normal file
152
Constness.h
Normal file
@ -0,0 +1,152 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace Alepha::Hydrogen ::detail:: Constness_m
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
/*!
|
||||
* Conditional constness primitive.
|
||||
*
|
||||
* C++17 and beyond have many conditional attributes on functions. Conditional `noexcept`,
|
||||
* conditional `explicit`, and even conditional instantiation. The `noexcept` and `explicit`
|
||||
* are conditional on a boolean condition. This enum permits making templates which
|
||||
* are conditionally const, depending upon instantiation.
|
||||
*
|
||||
* Simple example:
|
||||
*
|
||||
* ```
|
||||
* template< Constness constness >
|
||||
* struct IntWrapper
|
||||
* {
|
||||
* private:
|
||||
* int variable;
|
||||
*
|
||||
* public:
|
||||
* maybe_const_t< int &, constness > // This is sort of like if one could write `const( constness ) int &`
|
||||
* view() { return variable; }
|
||||
*
|
||||
* const int &
|
||||
* view() const { return variable; }
|
||||
* };
|
||||
*
|
||||
* using MutableIntWrapper= IntWrapper< Mutable >;
|
||||
* using ConstIntWrapper= IntWrapper< Const >;
|
||||
* ```
|
||||
*
|
||||
* Now `Constness< Mutable >` has a member `view` which returns `int &` and `Constness< Const >` has a member
|
||||
* `view` which returns `const int &`. This facility can be useful in implementing pairs of `const`/non-`const`
|
||||
* iterators, and other gadgets.
|
||||
*/
|
||||
enum Constness : bool
|
||||
{
|
||||
Const= true,
|
||||
Mutable= false,
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* Apply the `Constness` requested to the specified type.
|
||||
*
|
||||
* If the type isn't `const`, but `Constness` is set, then
|
||||
* it evaluates to `const T`.
|
||||
*/
|
||||
template< typename Type, Constness > struct maybe_const;
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type, Const >
|
||||
{
|
||||
using type= std::add_const_t< Type >;
|
||||
};
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type, Mutable >
|
||||
{
|
||||
using type= Type;
|
||||
};
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type &, Const >
|
||||
{
|
||||
using type= std::add_const_t< Type > &;
|
||||
};
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type &, Mutable >
|
||||
{
|
||||
using type= Type &;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Conditionally make `Type` `const`.
|
||||
*/
|
||||
template< typename Type, Constness constness >
|
||||
using maybe_const_t= typename maybe_const< Type, constness >::type;
|
||||
|
||||
/*!
|
||||
* Conditionally make `Type` into `const Type *`.
|
||||
*/
|
||||
template< typename Type, Constness constness >
|
||||
using maybe_const_ptr_t= std::add_pointer_t< maybe_const_t< Type, constness > >;
|
||||
|
||||
/*!
|
||||
* Conditionally call `std::as_const`.
|
||||
*
|
||||
* Sometimes `std::as_const` is appropriate to call, and sometimes it isn't.
|
||||
* In some cases, one might want to have type deduction driven by an expression
|
||||
* where, in a `const` "branch" `std::as_const` is called, but in a non-`const`
|
||||
* branch, it isn't. This facilitates that:
|
||||
*
|
||||
* ```
|
||||
* template< Constness constness >
|
||||
* struct IntWrapper
|
||||
* {
|
||||
* private:
|
||||
* int variable;
|
||||
*
|
||||
* public:
|
||||
* // `std::as_const` will be called when `constness` is true,
|
||||
* // and will be skipped otherwise. This permits the right
|
||||
* // client overload to be called
|
||||
* template< typename Function >
|
||||
* decltype( auto )
|
||||
* apply( Function func )
|
||||
* {
|
||||
* return func( maybe_as_const< constness >( variable ) );
|
||||
* }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
template< Constness constness, typename T >
|
||||
constexpr auto &
|
||||
maybe_as_const( T &t ) noexcept
|
||||
{
|
||||
if constexpr( constness ) return std::as_const( t );
|
||||
else return t;
|
||||
}
|
||||
|
||||
template< Constness constness, typename T >
|
||||
constexpr decltype( auto )
|
||||
maybe_as_const( const T &t ) noexcept
|
||||
{
|
||||
if constexpr( constness ) return std::as_const( t );
|
||||
else static_assert( dependent_value< false, T > );
|
||||
}
|
||||
|
||||
template< Constness constness, typename T >
|
||||
void maybe_as_const( T && )= delete;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::inline exports::inline Constness_m
|
||||
{
|
||||
using namespace detail::Constness_m::exports;
|
||||
}
|
3
Constness.test/0.cc
Normal file
3
Constness.test/0.cc
Normal file
@ -0,0 +1,3 @@
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "../Constness.h"
|
1
Constness.test/CMakeLists.txt
Normal file
1
Constness.test/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
unit_test( 0 )
|
Reference in New Issue
Block a user