1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
#include <iostream>
#include <type_traits>
// check if T has a nested apply that can be instantiated with specified template arguments
template < typename T, typename... ARGS > struct has_specified_template_apply
{
template < typename U >
static std::true_type test( U, typename U::template apply<ARGS...>* = nullptr ) ;
static std::false_type test(...) ;
using type = decltype( test( std::declval<T>() ) ) ;
static constexpr bool value = type{} ;
};
// check if T has a non-template apply
template < typename T > struct has_non_template_apply
{
template < typename U >
static std::true_type test( U, typename U::apply* = nullptr ) ;
static std::false_type test(...) ;
using type = decltype( test( std::declval<T>() ) ) ;
static constexpr bool value = type{} ;
};
namespace detail
{
template < typename... ARGS > struct pack
{ static constexpr std::size_t PACK_SIZE = sizeof...(ARGS) ; } ;
template < unsigned int N, typename... ARGS > struct repeat
{ using type = typename repeat< N-1, ARGS..., ARGS... >::type ; };
template < typename... ARGS > struct repeat< 0, ARGS...>
{ using type = pack<ARGS...> ; };
}
// check if T has a nested variadic template apply (with template type parameters)
template < typename T, unsigned int N = 16 > // check for apply with 2^N template parameters
struct has_variadic_template_apply
{
template < typename U, typename... ARGS >
static std::true_type test( U, detail::pack<ARGS...>, typename U::template apply<ARGS...>* = nullptr ) ;
static std::false_type test(...) ;
using type = decltype( test( std::declval<T>(), typename detail::repeat<N,void>::type{} ) ) ;
static constexpr bool value = type{} ;
};
template < typename T > void test()
{
std::cout << typeid(T).name() << '\n'<< std::boolalpha
<< "has_non_template_apply? " << has_non_template_apply<T>::value
<< "\nhas_specified_template_apply<T,int,char> ? "
<< has_specified_template_apply<T,int,char>::value
<< "\nhas_specified_template_apply<T,int,char,double,void> ? "
<< has_specified_template_apply<T,int,char,double,void>::value
<< "\nhas_variadic_template_apply? " << has_variadic_template_apply<T>::value
<< "\n\n" ;
}
template < typename... > struct type_list ;
template <> struct type_list<> { static void test() {} } ;
template < typename FIRST, typename... REST > struct type_list< FIRST, REST... >
{ static void test() { ::test<FIRST>() ; type_list<REST...>::test() ; } };
struct one {};
struct two { using apply = void ; };
struct three { template < typename, typename > struct apply{}; };
struct four { template < typename, typename... > struct apply{}; };
struct five
{
template < typename A, typename B,
typename = typename std::enable_if< std::is_pointer<B>::value >::type >
struct apply {};
};
int main()
{
type_list< one, two, three, four, std::is_pod<int> >::test() ;
std::cout << "is there a five::apply< int, void* > ? "
<< has_specified_template_apply< five, int, void* >::value << '\n' // true
<< "is there a five::apply< int, double& > ? "
<< has_specified_template_apply< five, int, double& >::value << '\n' ; // false
}
|