Library: finish new form of the type rebinding trait
This commit is contained in:
parent
1047f2f245
commit
674201f5ea
2 changed files with 121 additions and 91 deletions
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
VALUE-TYPE-BINDING.hpp - control type variations for IterAdapter
|
||||
VALUE-TYPE-BINDING.hpp - control type variations for custom containers
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -21,14 +21,31 @@
|
|||
*/
|
||||
|
||||
/** @file value-type-binding.hpp
|
||||
** Type re-binding helper template for IterAdapter and friends.
|
||||
** Type re-binding helper template for custom containers and adapters.
|
||||
** This header defines a trait template which is used by the Iterator
|
||||
** adapters to figure out the value-, pointer- and reference types
|
||||
** when wrapping iterators or containers. For extending the use of
|
||||
** Iterator adapters and Iter-tools to situations involving const
|
||||
** iterators or custom containers, explicit specialisations
|
||||
** might be injected prior to instantiating the Iterator adapter
|
||||
** template.
|
||||
** adapters and similar custom containers to figure out the value-,
|
||||
** pointer- and reference types when wrapping iterators or containers.
|
||||
**
|
||||
** When writing a generic container or adapter, there is typically some point
|
||||
** where you'd need some variation of the payload type: you may want to expose
|
||||
** a reference, or you might need a pointer to the type, to implement a forwarding
|
||||
** `operator->()`. On a technical level, this turns out surprisingly tricky, since
|
||||
** we often don't know the exact "incantation" of the payload type and might thus
|
||||
** end up forming a pointer to a rvalue reference or likewise illegal constructs.
|
||||
**
|
||||
** Within the STL, there is a convention to provide nested typedefs to indicate
|
||||
** type variations in relation to the basic payload type of the container. We
|
||||
** follow this convention and support especially the
|
||||
** - `value_type`
|
||||
** - a simple (LValue) reference to the payload
|
||||
** - a pointer at the payload.
|
||||
**
|
||||
** A custom container should likewise provide such type definitions, and the
|
||||
** type rebinding helper template defined in this header makes it easy to
|
||||
** provide such nested type definitions in a flexible way. This usage also
|
||||
** creates an *Extension Point*: when some payload type requires special
|
||||
** treatment, an explicit specialisation to this rebinding trait may be
|
||||
** injected alongside with the definition of the payload type.
|
||||
**
|
||||
** @see iter-adapter.hpp
|
||||
** @see scope-path.hpp usage example (explicit specialisation)
|
||||
|
|
@ -40,8 +57,7 @@
|
|||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
//#include "lib/meta/duck-detector.hpp" ////////TODO
|
||||
#include "lib/meta/util.hpp" ////////TODO
|
||||
#include "lib/meta/util.hpp"
|
||||
|
||||
|
||||
|
||||
|
|
@ -49,7 +65,7 @@
|
|||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
namespace {
|
||||
namespace { // Helper trait to detect nested value_type binding definitions
|
||||
|
||||
template<typename TY>
|
||||
class has_nested_ValueTypeBindings
|
||||
|
|
@ -71,6 +87,10 @@ namespace meta {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal helper template to pick up nested value type definitions
|
||||
*/
|
||||
template<typename TY, typename SEL =void>
|
||||
struct ValueTypeBinding
|
||||
{
|
||||
|
|
@ -79,10 +99,7 @@ namespace meta {
|
|||
typedef TY* pointer;
|
||||
};
|
||||
|
||||
/**
|
||||
* specialisation for classes providing
|
||||
* STL style type binding definitions themselves
|
||||
*/
|
||||
/** specialisation for classes providing STL style type binding definitions */
|
||||
template<typename TY>
|
||||
struct ValueTypeBinding<TY, enable_if<has_nested_ValueTypeBindings<TY>> >
|
||||
{
|
||||
|
|
@ -92,13 +109,17 @@ namespace meta {
|
|||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Type re-binding helper template for creating nested typedefs
|
||||
* for use by IterAdapter or similar "Lumiera Forward Iterators".
|
||||
* This trait provides a value-, reference- and pointer type,
|
||||
* similar to what the STL does.
|
||||
* for use by custom containers and iterator adapters or similar.
|
||||
* - this trait provides a value-, reference- and pointer type,
|
||||
* similar to what the STL does.
|
||||
* - references are stripped, otherwise the base type is passed through
|
||||
* - _but_ when the base type in turn provides such nested typedefs,
|
||||
* they are picked up and retrieved as result.
|
||||
* @note client code might define specialisations
|
||||
* to handle tricky situations (like const_reverse_iter)
|
||||
* to handle tricky situations (like e.g. const_reverse_iter)
|
||||
*/
|
||||
template<typename TY>
|
||||
struct TypeBinding
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
ValueTypeBinding(Test) - human readable simplified display of C++ types
|
||||
ValueTypeBinding(Test) - verify handling of value_type definitions on custom containers
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -47,7 +47,7 @@ namespace test{
|
|||
struct Outer
|
||||
{
|
||||
struct Inner
|
||||
{
|
||||
{
|
||||
T val;
|
||||
};
|
||||
|
||||
|
|
@ -57,7 +57,6 @@ namespace test{
|
|||
};
|
||||
|
||||
struct Space { };
|
||||
using Join = ulong;
|
||||
|
||||
template<typename X>
|
||||
struct Bugg
|
||||
|
|
@ -161,7 +160,7 @@ namespace test{
|
|||
* to indicate those types. The meta::TypeBinding helper allows to pick up such
|
||||
* definitions, and additionally it levels and unifies access for various combinations
|
||||
* of primitive types, references and pointers. The purpose of this test is to verify
|
||||
* and document this behaviour.
|
||||
* and document this behaviour.
|
||||
*
|
||||
* @see value-type-binding.hpp
|
||||
* @see lib::RangeIter
|
||||
|
|
@ -173,94 +172,104 @@ namespace test{
|
|||
void
|
||||
run (Arg)
|
||||
{
|
||||
// verify the type diagnostics helper...
|
||||
CHECK ("int" == showType<int >() );
|
||||
CHECK ("int&" == showType<int& >() );
|
||||
CHECK ("int &&" == showType<int&& >() );
|
||||
CHECK ("int const&" == showType<int const& >() );
|
||||
CHECK ("const int &&" == showType<int const&& >() );
|
||||
CHECK ("int *" == showType<int * >() );
|
||||
CHECK ("const int *" == showType<int const * >() );
|
||||
CHECK ("const int * const" == showType<int const * const >() );
|
||||
CHECK ("int const*&" == showType<int const * &>() );
|
||||
CHECK ("int const* const&" == showType<int const * const&>() );
|
||||
|
||||
|
||||
// Test fixture: the template Outer<T> provides nested value type bindings
|
||||
using OuterSpace = Outer<Space>;
|
||||
using Join = ulong;
|
||||
|
||||
cout << showType<OuterSpace::value_type>() <<endl;
|
||||
cout << showType<OuterSpace::reference>() <<endl;
|
||||
cout << showType<OuterSpace::pointer>() <<endl;
|
||||
CHECK ("Space" == showType<OuterSpace::value_type>() );
|
||||
CHECK ("Outer<Space>::Inner&" == showType<OuterSpace::reference>() );
|
||||
CHECK ("shared_ptr<Space>" == showType<OuterSpace::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<OuterSpace>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace>::pointer>() <<endl;
|
||||
// ...such nested type bindings will be picked up
|
||||
CHECK ("Space" == showType<TypeBinding<OuterSpace>::value_type>() );
|
||||
CHECK ("Outer<Space>::Inner&" == showType<TypeBinding<OuterSpace>::reference>() );
|
||||
CHECK ("shared_ptr<Space>" == showType<TypeBinding<OuterSpace>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Outer<Join>>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Outer<Join>>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Outer<Join>>::pointer>() <<endl;
|
||||
CHECK ("unsigned long" == showType<TypeBinding<Outer<Join>>::value_type>() );
|
||||
CHECK ("Outer<unsigned long>::Inner&" == showType<TypeBinding<Outer<Join>>::reference>() );
|
||||
CHECK ("shared_ptr<unsigned long>" == showType<TypeBinding<Outer<Join>>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Space>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Space>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Space>::pointer>() <<endl;
|
||||
// contrast this to a type without such nested bindings
|
||||
CHECK ("Space" == showType<TypeBinding<Space>::value_type>() );
|
||||
CHECK ("Space&" == showType<TypeBinding<Space>::reference>() );
|
||||
CHECK ("Space *" == showType<TypeBinding<Space>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<OuterSpace&>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace&>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace&>::pointer>() <<endl;
|
||||
// reference types will be levelled (reference stripped)
|
||||
CHECK ("Space" == showType<TypeBinding<OuterSpace&>::value_type>() );
|
||||
CHECK ("Outer<Space>::Inner&" == showType<TypeBinding<OuterSpace&>::reference>() );
|
||||
CHECK ("shared_ptr<Space>" == showType<TypeBinding<OuterSpace&>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<OuterSpace&&>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace&&>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace&&>::pointer>() <<endl;
|
||||
CHECK ("Space" == showType<TypeBinding<OuterSpace&&>::value_type>() );
|
||||
CHECK ("Outer<Space>::Inner&" == showType<TypeBinding<OuterSpace&&>::reference>() );
|
||||
CHECK ("shared_ptr<Space>" == showType<TypeBinding<OuterSpace&&>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<OuterSpace const&>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace const&>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace const&>::pointer>() <<endl;
|
||||
CHECK ("Space" == showType<TypeBinding<OuterSpace const&>::value_type>() );
|
||||
CHECK ("Outer<Space>::Inner&" == showType<TypeBinding<OuterSpace const&>::reference>() );
|
||||
CHECK ("shared_ptr<Space>" == showType<TypeBinding<OuterSpace const&>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<OuterSpace*>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace*>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace*>::pointer>() <<endl;
|
||||
// but a pointer counts as a different, primitive type. No magic here
|
||||
CHECK ("Outer<Space> *" == showType<TypeBinding<OuterSpace*>::value_type>() );
|
||||
CHECK ("Outer<Space>*&" == showType<TypeBinding<OuterSpace*>::reference>() );
|
||||
CHECK ("Outer<Space>* *" == showType<TypeBinding<OuterSpace*>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<const OuterSpace*>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<const OuterSpace*>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<const OuterSpace*>::pointer>() <<endl;
|
||||
CHECK ("const Outer<Space> *" == showType<TypeBinding<const OuterSpace*>::value_type>() );
|
||||
CHECK ("Outer<Space> const*&" == showType<TypeBinding<const OuterSpace*>::reference>() );
|
||||
CHECK ("Outer<Space> const* *" == showType<TypeBinding<const OuterSpace*>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<const OuterSpace * const>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<const OuterSpace * const>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<const OuterSpace * const>::pointer>() <<endl;
|
||||
CHECK ("const Outer<Space> * const" == showType<TypeBinding<const OuterSpace * const>::value_type>() );
|
||||
CHECK ("Outer<Space> const* const&" == showType<TypeBinding<const OuterSpace * const>::reference>() );
|
||||
CHECK ("Outer<Space> * const *" == showType<TypeBinding<const OuterSpace * const>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<OuterSpace * const>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace * const>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<OuterSpace * const>::pointer>() <<endl;
|
||||
CHECK ("Outer<Space> * const" == showType<TypeBinding<OuterSpace * const>::value_type>() );
|
||||
CHECK ("Outer<Space>* const&" == showType<TypeBinding<OuterSpace * const>::reference>() );
|
||||
CHECK ("Outer<Space> * const *" == showType<TypeBinding<OuterSpace * const>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Join>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Join>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Join>::pointer>() <<endl;
|
||||
// similar for a type without nested type bindings: references are levelled
|
||||
CHECK ("unsigned long" == showType<TypeBinding<Join>::value_type>() );
|
||||
CHECK ("unsigned long&" == showType<TypeBinding<Join>::reference>() );
|
||||
CHECK ("unsigned long *" == showType<TypeBinding<Join>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Join&>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Join&>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Join&>::pointer>() <<endl;
|
||||
CHECK ("unsigned long" == showType<TypeBinding<Join&>::value_type>() );
|
||||
CHECK ("unsigned long&" == showType<TypeBinding<Join&>::reference>() );
|
||||
CHECK ("unsigned long *" == showType<TypeBinding<Join&>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Join&&>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Join&&>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Join&&>::pointer>() <<endl;
|
||||
CHECK ("unsigned long" == showType<TypeBinding<Join&&>::value_type>() );
|
||||
CHECK ("unsigned long&" == showType<TypeBinding<Join&&>::reference>() );
|
||||
CHECK ("unsigned long *" == showType<TypeBinding<Join&&>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Join const&>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Join const&>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Join const&>::pointer>() <<endl;
|
||||
CHECK ("unsigned long" == showType<TypeBinding<Join const&>::value_type>() );
|
||||
CHECK ("unsigned long const&" == showType<TypeBinding<Join const&>::reference>() );
|
||||
CHECK ("const unsigned long *" == showType<TypeBinding<Join const&>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Join *>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Join *>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Join *>::pointer>() <<endl;
|
||||
//... but pointer types are not treated special in any way
|
||||
CHECK ("unsigned long *" == showType<TypeBinding<Join *>::value_type>() );
|
||||
CHECK ("unsigned long*&" == showType<TypeBinding<Join *>::reference>() );
|
||||
CHECK ("unsigned long* *" == showType<TypeBinding<Join *>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<const Join *>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<const Join *>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<const Join *>::pointer>() <<endl;
|
||||
CHECK ("const unsigned long *" == showType<TypeBinding<const Join *>::value_type>() );
|
||||
CHECK ("unsigned long const*&" == showType<TypeBinding<const Join *>::reference>() );
|
||||
CHECK ("unsigned long const* *" == showType<TypeBinding<const Join *>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<const Join * const>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<const Join * const>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<const Join * const>::pointer>() <<endl;
|
||||
CHECK ("const unsigned long * const" == showType<TypeBinding<const Join * const>::value_type>() );
|
||||
CHECK ("unsigned long const* const&" == showType<TypeBinding<const Join * const>::reference>() );
|
||||
CHECK ("unsigned long * const *" == showType<TypeBinding<const Join * const>::pointer>() );
|
||||
|
||||
cout << showType<TypeBinding<Join * const>::value_type>() <<endl;
|
||||
cout << showType<TypeBinding<Join * const>::reference>() <<endl;
|
||||
cout << showType<TypeBinding<Join * const>::pointer>() <<endl;
|
||||
|
||||
cout << showType<int>() <<endl;
|
||||
cout << showType<int&>() <<endl;
|
||||
cout << showType<int&&>() <<endl;
|
||||
cout << showType<int const&>() <<endl;
|
||||
cout << showType<int const&&>() <<endl;
|
||||
cout << showType<int *>() <<endl;
|
||||
cout << showType<int const *>() <<endl;
|
||||
cout << showType<int const * const>() <<endl;
|
||||
cout << showType<int const * &>() <<endl;
|
||||
cout << showType<int const * const&>() <<endl;
|
||||
CHECK ("unsigned long * const" == showType<TypeBinding<Join * const>::value_type>() );
|
||||
CHECK ("unsigned long* const&" == showType<TypeBinding<Join * const>::reference>() );
|
||||
CHECK ("unsigned long * const *" == showType<TypeBinding<Join * const>::pointer>() );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue