Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if a type is derived from a template class?

How can I determine if a type is derived from a template class? In particular, I need to determine if a template parameter has std::basic_ostream as a base class. Normally std::is_base_of is the tool for the job. However, std::is_base_of only works for complete types not class templates.

I'm looking for something like this.

template< typename T >
bool is_based_in_basic_ostream( T&& t )
{
   if( std::is_base_of< std::basic_ostream< /*anything*/>, T >::value )
   {
      return true;
   }
   else
   {
      return false;
   }
}

I'm sure this can be done I can't think how.

like image 293
deft_code Avatar asked May 13 '11 21:05

deft_code


2 Answers

I'm not aware of a short and concise way. But you can abuse overloading again

template< typename T, typename U >
std::true_type is_based_impl( std::basic_ostream<T, U> const volatile& );
std::false_type is_based_impl( ... );

template< typename T >
bool is_based_in_basic_ostream( T&& t ) {
  return decltype(is_based_impl(t))::value;
}

It will only detect public inheritance. Note that you can instead detect derivation from ios_base, which may work for you equally well (this test will also be positive for input streams, so it's only of limited applicability)

std::is_base_of<std::ios_base, T>
like image 177
Johannes Schaub - litb Avatar answered Oct 13 '22 22:10

Johannes Schaub - litb


Might something like Boost's is_instance_of be what you are after?

http://www.boost.org/doc/libs/1_46_1/boost/lambda/detail/is_instance_of.hpp

Here is the short version for 1-argument templates:

#include <iostream>
#include <type_traits>

template <template <typename> class F>
struct conversion_tester
{
        template <typename T>
        conversion_tester (const F<T> &);
};

template <class From, template <typename> class To>
struct is_instance_of
{
        static const bool value = std::is_convertible<From,conversion_tester<To>>::value;
};

template <typename T>
struct foo {};

template <typename T>
struct bar {};

int main()
{
        std::cout << is_instance_of<foo<int>,foo>::value << '\n'; // This will print '1'.
        std::cout << is_instance_of<bar<int>,foo>::value << '\n'; // This will print '0'.
}

Unfortunately, if you try to extend this to variadic templates, with current GCC (4.6.0) it will produce an error message. This SO answer implies that this is currently a problem of GCC and that the variadic template version is supposed to work according to the standard.

like image 27
bluescarni Avatar answered Oct 13 '22 23:10

bluescarni