diff --git a/Reflection/CMakeLists.txt b/Reflection/CMakeLists.txt index 76ddd72..2b2b843 100644 --- a/Reflection/CMakeLists.txt +++ b/Reflection/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory( tuplizeAggregate.test ) add_subdirectory( has_tagged_ctor.test ) +add_subdirectory( tagged_ctor_count.test ) diff --git a/Reflection/tagged_ctor_count.h b/Reflection/tagged_ctor_count.h new file mode 100644 index 0000000..66288c1 --- /dev/null +++ b/Reflection/tagged_ctor_count.h @@ -0,0 +1,92 @@ +static_assert( __cplusplus > 2020'99 ); + +#pragma once + +#include + +#include +#include +#include + +#include + +#include + +namespace Alepha::Hydrogen::Reflection ::detail:: tagged_ctor_count_m +{ + inline namespace exports {} + + namespace C + { + using namespace Reflection::detail::config_m::C; + } + + // Basic methodology here: I probe the number of arguments that an object can be constructed with, given the tag. + // I don't care what they actually are, as there's no easy way to hoist out what they are. However, for an + // object ctor, we have to get the exact right number. + // Therefore we just wind up finding the smallest-ordinality ctor with that tag. + + // The basic adaptable argument. Because it pretends to be anything, it can be used as a parameter in invoking + // any initialization method. + template< typename Forbidden > + struct argument + { + template< typename T > + requires( not Concepts::SameAs< T, Forbidden > ) + constexpr operator T (); + }; + + template< typename T, typename ... Args > + requires Concepts::ConstructibleFrom< T, Args... > + constexpr void construct( const std::tuple< Args... > & ); + + template< typename T, typename Tuple > + concept ConstructibleWithTuple= + requires( Tuple tup ) + { + { construct< T >( tup ) }; + }; + + template< typename Forbidden, typename Seq > + struct expand; + + template< typename Forbidden, std::size_t ... Ints > + struct expand< Forbidden, std::index_sequence< Ints... > > + { + using type= decltype( std::make_tuple( ( Ints, argument< Forbidden >{} )... ) ); + }; + + template< typename Forbidden, std::size_t argcnt > + using expand_t= typename expand< Forbidden, std::make_index_sequence< argcnt > >::type; + + template< typename T, typename tag, std::size_t args > + concept ConstructibleWith= + ConstructibleWithTuple< T, decltype( std::tuple_cat( std::declval< expand_t< T, args > >(), std::declval< std::tuple< tag > >() ) ) >; + + // The first step is to just start it all off with a blank sequence and walk forward from there. + // The default arguments cause it to start with the blank sequence, even if it doesn't match this + // case in the specialization selection. + template< typename T, typename tag, std::size_t cnt= 0 > + struct tagged_ctor_count + : tagged_ctor_count< T, tag, cnt + 1 > {}; + + template< typename T, typename tag, std::size_t depth > + requires ConstructibleWith< T, tag, depth > + struct tagged_ctor_count< T, tag, depth > + // Size is 1 more than the depth we probed, since that also accounts for the tag. + : std::integral_constant< std::size_t, depth + 1 > {}; + + namespace exports + { + template< typename T, typename tag > + constexpr std::size_t tagged_ctor_count_v= tagged_ctor_count< T, tag >::value; + + template< typename T, typename tag > + struct tagged_ctor_count : std::integral_constant< std::size_t, tagged_ctor_count_v< T, tag > > {}; + } +} + +namespace Alepha::Hydrogen::Reflection::inline exports::inline tagged_ctor_count_m +{ + using namespace detail::tagged_ctor_count_m::exports; +} diff --git a/Reflection/tagged_ctor_count.test/0.cc b/Reflection/tagged_ctor_count.test/0.cc new file mode 100644 index 0000000..8ed5d54 --- /dev/null +++ b/Reflection/tagged_ctor_count.test/0.cc @@ -0,0 +1,22 @@ +static_assert( __cplusplus > 2020'99 ); + +#include + +#include +#include +#include + +namespace +{ + using namespace Alepha::Testing::literals; + + struct tag {}; + struct tag2 {}; + struct instance + { + explicit instance( int a, float b, char c, double d, tag t ); + }; + + using namespace Alepha::Reflection::exports::tagged_ctor_count_m; + static_assert( tagged_ctor_count_v< instance, tag > == 5 ); +} diff --git a/Reflection/tagged_ctor_count.test/CMakeLists.txt b/Reflection/tagged_ctor_count.test/CMakeLists.txt new file mode 100644 index 0000000..b099603 --- /dev/null +++ b/Reflection/tagged_ctor_count.test/CMakeLists.txt @@ -0,0 +1 @@ +unit_test( 0 )