Detecting compilation type parameter type time types

I know several methods to determine if a given class has a function with the specified signature. However, I would like to display the signature at compile time. Consider:

struct test_class { void test( int a ); void test( float b ); }; 

I can use decltype and SFINAE to detect the presence of the specified test () with simple syntax like has_test<test_class,int>(); . However, I would like something like test_types<test_class>::types -> mpl::list< int, float > . Does anyone have a reasonable idea how to do this? The requirement is that a list of detected types cannot be prepared (therefore, it will detect any test( T ) , and not just the ones that we "register".

+5
source share
2 answers

If you can afford to decorate test() overloads in an equivalent way (it's ugly, I know, maybe you can come out with something more beautiful):

 struct test_class { param<int> test( int a, param_id<0> ={} ); param<float> test( float a, param_id<1> ={} ); }; 

then something like this should work ( kind of matching godbolt ):

 template<typename T> struct param{ using type = T; }; template<int I> struct param_id{}; template<typename... T> struct type_list{}; struct anything{ template<typename T> operator T&&(); }; template<int I> struct matcher { template<typename T, typename E = std::enable_if_t<std::is_same<T,param_id<I>>::value> > operator T(); }; template<typename T,int I,typename = std::void_t<>,typename... Ts> struct test_types_impl{ using type = type_list<Ts...>; }; template<typename T,int I,typename... Ts> struct test_types_impl<T,I,std::void_t<decltype(std::declval<T>().test( anything{}, matcher<I>{} ))>,Ts...>: test_types_impl<T,I+1,void,Ts...,typename decltype(std::declval<T>().test( anything{}, matcher<I>{} ))::type> { }; template<typename T> struct test_types{ using type = typename test_types_impl<T,0>::type; }; struct test_class { param<int> test( int a, param_id<0> ={} ); param<float> test( float a, param_id<1> ={} ); }; static_assert( std::is_same_v<test_types<test_class>::type, type_list<int,float>> ); 

this requires at least constructive argument types and C ++ 17 (but I think that it can be made to work in C ++ 11, and with any type).

param_id may be omitted if you manage to get full ordering by the set of allowed parameter types. Maybe we can even omit param<T> somehow, although we are not sure (expecting feedback from the OP for this :))

+2
source

IIUC, you want to apply some class checks to the type list and copy (?) The results. If so, you can use code like:

 #include <boost/mpl/list.hpp> #include <boost/mpl/pop_front.hpp> #include <boost/mpl/empty.hpp> #include <boost/mpl/front.hpp> #include <type_traits> template <typename ClassT, typename ParamT> struct check : public std::true_type { }; // template <typename ClassT> // struct check<ClassT, double> : public std::false_type // { // }; template <typename ClassT, typename ParamList, bool list_empty> struct apply; template <typename ClassT, typename ParamList> struct apply <ClassT, ParamList, true> : public std::true_type{}; template <typename ClassT, typename ParamList> struct apply <ClassT, ParamList, false> : public std::integral_constant< bool, apply< ClassT, typename boost::mpl::pop_front<ParamList>::type, boost::mpl::empty<typename boost::mpl::pop_front<ParamList>::type>::value >::value && check<ClassT, typename boost::mpl::front<ParamList>::type>::value> { }; class Test { }; #include <iostream> int main(int , char ** ) { std::cout << std::boolalpha << apply<Test, boost::mpl::list<int, float, double>, false>::value << std::endl; return 0; } 

Suppose check is your custom check that gave std::true_type or std::false_type . If you uncomment the specialization for double , the result will change from true to false .

+1
source

Source: https://habr.com/ru/post/1274570/


All Articles