Boost logo

Boost :

From: Jaakko Jarvi (jajarvi_at_[hidden])
Date: 2001-11-20 12:01:16


Hi,

I needed to find out whether a given type was a stream or not.
The is_convertible template wasn't useful, as the stream could be
any instantiation of basic_stream. I just needed to know whether the type
was any instantiation of a basic_stream, or derived from any instantiation
of a basic_stream.

I wrote some traits classes for this purpose. They reside in
boost/lambda/detail/is_instance_of.hpp in lambda_development branch,
but I think a better place for those classes would be the type_traits
library - if they're considered to be generally useful.

The usage is as:

is_instance_of_2<std::istream, basic_stream>::value // true

is_instance_of_2<int, basic_stream>::value // false

There are separate templates (is_instance_of_1, is_instance_of_2, ...)
for different numbers of template parameters of the second argument.

As a side note, this seems to be a case of template template parameter
use, where the same effect cannot be achieved with other language
constructs.

Below is the implementation and a small test program (compiles with gcc
and KCC, gcc requires some tricks like with is_convertible)

Cheers, Jaakko

-- Jaakko Järvi, jajarvi_at_[hidden]

// -------------------------------------------------------------------
// -------------------------------------------------------------------

// is_instance_of --------------------------------
//
// is_instance_of_n<A, B>::value is true, if type A is
// an instantiation of a template B, or A derives from an instantiation
// of template B
// //
//
// n is the number of template arguments for B
//
// Example:
// is_instance_of_2<std::istream, basic_stream>::value == true

#include <iostream>

typedef char yes_type;
typedef double no_type;

#ifndef __GNUC__

  // store a pointer, as passing non-PODs through ellipsis results in
  // warnings in some compilers

template <class From, template <class> class To>
struct is_instance_of_1
{
private:
   static no_type _m_check(...);

   template <class T1>
   static yes_type _m_check(const To<T1>*);

   static From* _m_from;

public:
   static const bool value = sizeof( _m_check(_m_from) ) ==
sizeof(yes_type);

   void foo();
};

template <class From, template <class, class> class To>
struct is_instance_of_2
{
private:
   static no_type _m_check(...);

   template <class T1, class T2>
   static yes_type _m_check(const To<T1, T2>*);

   static From* _m_from;

public:
   static const bool value = sizeof( _m_check(_m_from) ) ==
sizeof(yes_type);

   void foo();
};

#else
// GCC version

template <class From, template <class> class To>
struct is_instance_of_1
{

private:
   static no_type _m_check(...);

   template <class T1>
   static yes_type _m_check(const To<T1>*);

   static From* _m_from;

public:
   static const bool value;
   void foo();
};

template <class From, template <class> class To>
const bool
is_instance_of_1<From, To>::value
  = sizeof( _m_check(_m_from) ) == sizeof(yes_type);

template <class From, template <class, class> class To>
struct is_instance_of_2
{

private:
   static no_type _m_check(...);

   template <class T1, class T2>
   static yes_type _m_check(const To<T1, T2>*);

   static From* _m_from;

public:
   static const bool value;
   void foo();
};

template <class From, template <class, class> class To>
const bool
is_instance_of_2<From, To>::value
  = sizeof( _m_check(_m_from) ) == sizeof(yes_type);

#endif

template <class T1> struct A1 {};
template <class T1, class T2> struct A2 {};

class B1 : public A1<int> {};
class B2 : public A2<int,int> {};

// classes that are convertible to classes that derive from A instances
// This is not enough to make the test succeed

class C1 { public: operator A1<int>() { return A1<int>(); } };
class C2 { public: operator B2() { return B2(); } };

int main() {

using std::cout;

cout << is_instance_of_1<B1, A1>::value; // true
cout << is_instance_of_1<A1<float>, A1>::value;// true
cout << is_instance_of_1<int, A1>::value;// false
cout << is_instance_of_1<C1, A1>::value;// false

cout << is_instance_of_2<B2, A2>::value;// true
cout << is_instance_of_2<A2<int, float>, A2>::value;// true
cout << is_instance_of_2<int, A2>::value;// false
cout << is_instance_of_2<C2, A2>::value;// false

cout << "\n";

return 0;

}

// -------------------------------------------------------------------
// -------------------------------------------------------------------


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk