forked from Alepha/Alepha
Fixed tagged ctor argument inspection code.
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
add_subdirectory( tuplizeAggregate.test )
|
add_subdirectory( tuplizeAggregate.test )
|
||||||
add_subdirectory( has_tagged_ctor.test )
|
add_subdirectory( has_tagged_ctor.test )
|
||||||
add_subdirectory( tagged_ctor_count.test )
|
add_subdirectory( tagged_ctor_count.test )
|
||||||
|
add_subdirectory( tagged_ctor_arg.test )
|
||||||
|
234
Reflection/tagged_ctor_arg.h
Normal file
234
Reflection/tagged_ctor_arg.h
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
static_assert( __cplusplus > 2020'99 );
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Alepha/Alepha.h>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <Alepha/Concepts.h>
|
||||||
|
|
||||||
|
#include <Alepha/Reflection/detail/config.h>
|
||||||
|
|
||||||
|
#include <Alepha/Reflection/has_tagged_ctor.h>
|
||||||
|
#include <Alepha/Reflection/tagged_ctor_count.h>
|
||||||
|
|
||||||
|
namespace Alepha::Hydrogen::Reflection ::detail:: tagged_ctor_arg_m
|
||||||
|
{
|
||||||
|
inline namespace exports {}
|
||||||
|
|
||||||
|
namespace C
|
||||||
|
{
|
||||||
|
using namespace Reflection::detail::config_m::C;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace protection
|
||||||
|
{
|
||||||
|
//template< typename Fake, typename Dummy >
|
||||||
|
//inline void get_argument_type( Fake, Dummy ) {}
|
||||||
|
|
||||||
|
template< typename Type, typename tag, std::size_t index >
|
||||||
|
struct lookup_helper
|
||||||
|
{
|
||||||
|
template< typename Dummy, typename >
|
||||||
|
friend constexpr auto get_argument_type( const lookup_helper< Type, tag, index > &, Dummy );
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename Type, typename tag, std::size_t index, typename arg_type >
|
||||||
|
struct argument_extractor
|
||||||
|
{
|
||||||
|
template< typename Dummy, typename= std::enable_if_t< std::is_same_v< Dummy, std::nullptr_t > > >
|
||||||
|
friend constexpr auto
|
||||||
|
get_argument_type( const lookup_helper< Type, tag, index > &, Dummy )
|
||||||
|
{
|
||||||
|
return std::type_identity< arg_type >();
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr void member() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename Type, typename tag, std::size_t index >
|
||||||
|
struct exporting_argument
|
||||||
|
{
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename ArgType,
|
||||||
|
auto= argument_extractor< Type, tag, index, std::decay_t< ArgType > >::member//,
|
||||||
|
//typename= std::enable_if_t< not std::is_same_v< ArgType, Type > >
|
||||||
|
>
|
||||||
|
constexpr operator ArgType () const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename Forbidden >
|
||||||
|
struct argument
|
||||||
|
{
|
||||||
|
template< typename T, typename= std::enable_if_t< not std::is_same_v< T, Forbidden > > >
|
||||||
|
constexpr operator T ();
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T, typename ... Args, typename= std::enable_if_t< std::is_constructible_v< T, Args... > > >
|
||||||
|
constexpr void construct( std::tuple< Args... > && );
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename T,
|
||||||
|
typename tag,
|
||||||
|
typename sequence= std::index_sequence<>,
|
||||||
|
typename= void,
|
||||||
|
typename= void
|
||||||
|
>
|
||||||
|
struct extract_all_ctor_arguments
|
||||||
|
: extract_all_ctor_arguments< T, tag, std::make_index_sequence< sequence::size() + 1 > > {};
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename T,
|
||||||
|
typename tag
|
||||||
|
>
|
||||||
|
struct extract_all_ctor_arguments< T, tag, std::make_index_sequence< C::max_ctor_size >, void >
|
||||||
|
{
|
||||||
|
struct impossible;
|
||||||
|
static_assert( std::is_same_v< impossible, T >, "Max recursion reached." );
|
||||||
|
};
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename T,
|
||||||
|
typename tag,
|
||||||
|
std::size_t ... positions
|
||||||
|
>
|
||||||
|
struct extract_all_ctor_arguments
|
||||||
|
<
|
||||||
|
T,
|
||||||
|
tag,
|
||||||
|
std::index_sequence< positions... >,
|
||||||
|
std::void_t
|
||||||
|
<
|
||||||
|
decltype
|
||||||
|
(
|
||||||
|
construct< T >( std::tuple_cat
|
||||||
|
(
|
||||||
|
std::make_tuple( ( positions, std::declval< argument< T > >() )... ),
|
||||||
|
std::make_tuple( std::declval< tag >() )
|
||||||
|
) )
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename int_const,
|
||||||
|
typename= std::void_t
|
||||||
|
<
|
||||||
|
decltype
|
||||||
|
(
|
||||||
|
construct< T >( std::tuple_cat
|
||||||
|
(
|
||||||
|
std::make_tuple( ( positions, std::declval< exporting_argument< T, tag, positions > >() )... ),
|
||||||
|
std::make_tuple( std::declval< tag >() )
|
||||||
|
) )
|
||||||
|
)
|
||||||
|
>
|
||||||
|
>
|
||||||
|
struct constant_wrapper
|
||||||
|
{
|
||||||
|
// Replay the construction in this body, to cause the friend injection of our
|
||||||
|
// exporters for detected params to happen only once. If we didn't match, we don't
|
||||||
|
// want to create false overloads. The standard is murky on which return type
|
||||||
|
// dominates, in those cases. We are abusing something CWG doesn't like, but they've
|
||||||
|
// had over a decade to fix it... and some future standard will provide real reflection
|
||||||
|
// and this hack can vanish.
|
||||||
|
using type= std::conditional_t
|
||||||
|
<
|
||||||
|
true,
|
||||||
|
typename int_const::type,
|
||||||
|
// Force instantiation of tag extractor:
|
||||||
|
decltype( argument_extractor< T, tag, sizeof...( positions ), tag >::member() )
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
using type= typename constant_wrapper< std::integral_constant< std::size_t, 1 + sizeof...( positions ) > >::type;
|
||||||
|
static constexpr std::size_t value= type::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename T,
|
||||||
|
typename tag,
|
||||||
|
std::size_t index
|
||||||
|
>
|
||||||
|
struct tagged_ctor_extract_impl
|
||||||
|
{
|
||||||
|
using type= typename decltype( get_argument_type(
|
||||||
|
std::declval< lookup_helper< T, tag, index > >(), nullptr ) )::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename T,
|
||||||
|
typename tag,
|
||||||
|
std::size_t index,
|
||||||
|
auto fake_type= extract_all_ctor_arguments< T, tag >::value
|
||||||
|
>
|
||||||
|
struct tagged_ctor_extract
|
||||||
|
{
|
||||||
|
using type= typename tagged_ctor_extract_impl< T, tag, index >::type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace impl
|
||||||
|
{
|
||||||
|
template< typename T, typename tag, std::size_t index >
|
||||||
|
struct tagged_ctor_arg
|
||||||
|
{
|
||||||
|
using type= std::decay_t< typename protection::tagged_ctor_extract< T, tag, index >::type >;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T, typename tag, std::size_t index >
|
||||||
|
using tagged_ctor_arg_t= typename tagged_ctor_arg< T, tag, index >::type;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace build_impl
|
||||||
|
{
|
||||||
|
template< typename T, typename tag, std::size_t size, std::size_t index= 0 >
|
||||||
|
struct build_ctor_tuple
|
||||||
|
{
|
||||||
|
using type= decltype
|
||||||
|
(
|
||||||
|
std::tuple_cat
|
||||||
|
(
|
||||||
|
std::declval< std::tuple< impl::tagged_ctor_arg_t< T, tag, index > > >(),
|
||||||
|
std::declval< typename build_ctor_tuple< T, tag, size, index + 1 >::type >()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T, typename tag, std::size_t size >
|
||||||
|
struct build_ctor_tuple< T, tag, size, size >
|
||||||
|
{
|
||||||
|
using type= std::tuple<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T, typename tag >
|
||||||
|
struct build_ctor_tuple_wrapper
|
||||||
|
{
|
||||||
|
static_assert( has_tagged_ctor_v< T, tag > );
|
||||||
|
inline static constexpr auto sz= tagged_ctor_count_v< T, tag >;
|
||||||
|
using type= typename build_ctor_tuple< T, tag, sz >::type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace exports
|
||||||
|
{
|
||||||
|
template< typename T, typename tag >
|
||||||
|
using tagged_ctor_args_t= typename build_impl::build_ctor_tuple_wrapper< T, tag >::type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Alepha::Hydrogen::Reflection::inline exports::inline tagged_ctor_arg_m
|
||||||
|
{
|
||||||
|
using namespace detail::tagged_ctor_arg_m::exports;
|
||||||
|
}
|
||||||
|
|
47
Reflection/tagged_ctor_arg.test/0.cc
Normal file
47
Reflection/tagged_ctor_arg.test/0.cc
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
static_assert( __cplusplus > 2020'99 );
|
||||||
|
|
||||||
|
#include <Alepha/Reflection/tagged_ctor_arg.h>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct tag {};
|
||||||
|
struct tag2 {};
|
||||||
|
struct fake {};
|
||||||
|
struct instance
|
||||||
|
{
|
||||||
|
// There are arity issues with the tagged ctor lookup.
|
||||||
|
// No other ctor can have the same arity as a tagged ctor.
|
||||||
|
// (Each tagged ctor has to have a unique arity.)
|
||||||
|
//
|
||||||
|
// If they do, it causes "redefinition errors" from template
|
||||||
|
// friend injection. I believe that the reason for this is
|
||||||
|
// that each `exporting_argument` object winds up generating
|
||||||
|
// several `operator T` overloads, one for each object ctor
|
||||||
|
// that it attempts to convert to. Thus we wind up with
|
||||||
|
// duplicate bindings. While this is annoying, it's not
|
||||||
|
// significantly different to the `function_traits` inspector
|
||||||
|
// in that it requires a single overload. If duplicate
|
||||||
|
// arity overloads are needed, padding dummy arguments can be
|
||||||
|
// used are needed. These dummies cannot be defaulted.
|
||||||
|
// Further, the tag arguments should not be defaulted, as that
|
||||||
|
// creates pseudo-overloads with the same arity. This advice
|
||||||
|
// not to default tags applies only when dealing with
|
||||||
|
// overloads.
|
||||||
|
//
|
||||||
|
// The hope is that in a future version of C++ there will
|
||||||
|
// be a true reflection mechanism for ctors -- and thus that
|
||||||
|
// facility can be used as a replacement for this reflection
|
||||||
|
// hack.
|
||||||
|
explicit instance( int a, float b, char c, double d, tag t );
|
||||||
|
explicit instance( long, long, long, long, fake, tag2 t );
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace Alepha::Reflection::exports::tagged_ctor_arg_m;
|
||||||
|
using tuple= tagged_ctor_args_t< instance, tag >;
|
||||||
|
std::tuple< int, float, char, double, tag > t= tuple{};
|
||||||
|
static_assert( std::is_same_v< tuple, std::tuple< int, float, char, double, tag > > );
|
||||||
|
using tuple2= tagged_ctor_args_t< instance, tag2 >;
|
||||||
|
static_assert( std::is_same_v< tuple2, std::tuple< long, long, long, long, fake, tag2 > > );
|
||||||
|
}
|
1
Reflection/tagged_ctor_arg.test/CMakeLists.txt
Normal file
1
Reflection/tagged_ctor_arg.test/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
unit_test( 0 )
|
Reference in New Issue
Block a user