简体   繁体   中英

How to find, from which template-layers is object composed of?

How can I use templates, to find out, from which types is type composed of when using template layers?

Let's have

template <typename Super>
class A : public Super {};

template <typename Super>
class B : public Super {};

template <typename Super>
class C : public Super {};

class Blank{};

template <typename CombinedType>
void printTypeComponents(const CombinedType & t) { ... }

int main()
{
     typedef A<B<C<Blank>>> ComposedType;
     ComposedType ct;
     printTypeComponents(ct);

     typedef A<C<Blank>> ComposedType2;
     ComposedType2 ct2;
     printTypeComponents(ct2);
}

I am attaching my try, wrong of course (works only if object is composed from all tested types, since tested types actually exists), but you can easily see from it, what my aim is

#include <boost/type_traits/is_base_of.hpp>
#include <iostream>

template <typename Super>
class A : public Super 
{
public:
    typedef A<Super> AComponent;
};

template <typename Super>
class B : public Super 
{
public:
    typedef B<Super> BComponent;
};

template <typename Super>
class C : public Super 
{
public:
    typedef C<Super> CComponent;
};

class Blank{};

template <typename CombinedType>
void printTypeComponents(const CombinedType & t)
{
    if(boost::is_base_of<Blank, CombinedType::AComponent>::value)
        std::cout << "composed of A \n";

    if(boost::is_base_of<Blank, CombinedType::BComponent>::value)
        std::cout << "composed of B \n";

    if(boost::is_base_of<Blank, CombinedType::CComponent>::value)
        std::cout << "composed of C \n";
}

int main()
{
     typedef A<B<C<Blank>>> ComposedType;
     ComposedType ct;
     printTypeComponents(ct);

     //typedef A<C<Blank>> ComposedType2;
     //ComposedType2 ct2;
     //printTypeComponents(ct2);
}

I am using MSVC2010

Thank you!

EDIT: I am not actually interested in names of types... I want to use it like:

if(composedOfA)
    doSomeCharacteristicStuffFromA(); //member function of A

if(composedOfB)
    doSomeCharacteristicStuffFromB(); //member function of B

My attempt ( without using C++0x feature(s))

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

struct null{};

template<typename> 
struct split
{
   typedef null Ct;
   typedef null At;
};

template<template<typename> class C, typename T> 
struct split<C<T> >
{
   typedef C<null> Ct; //class template 
   typedef T      At;  //argument type
};

template<template<typename> class C> 
struct split<C<Blank> >
{
   typedef C<null> Ct; //class template 
   typedef Blank   At;  //argument type
};

template<typename T, typename U>
struct is_same
{
   static const bool value = false;
};
template<typename T>
struct is_same<T,T>
{
   static const bool value = true;
};

typedef  A<null> anull;
typedef  B<null> bnull;
typedef  C<null> cnull;

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

template <typename CombinedType>
void printTypeComponents(const CombinedType & t)
{
     typedef typename split<CombinedType>::Ct Ct;
     typedef typename split<CombinedType>::At At;

     if ( is_same<Ct,anull>::value ) 
           cout << "A" << endl;
     else if ( is_same<Ct,bnull>::value )
           cout << "B" << endl;
     else if ( is_same<Ct,cnull>::value )
           cout << "C" << endl;

     if ( !is_same<At,Blank>::value )
           printTypeComponents(At());
     else
           cout << "Blank" << endl;
}

Test code:

int main()
{
     typedef A<B<C<Blank> > > ComposedType;
     ComposedType ct;
     printTypeComponents(ct);

     cout<<"-------"<<endl;

     typedef A<C<Blank> > ComposedType2;
     ComposedType2 ct2;
     printTypeComponents(ct2);
}

Output:

A
B
C
Blank
-------
A
C
Blank

Online Demo: http://ideone.com/T5nD4

Exploiting your structure, what about:

template <template <typename> class X, typename T>
void print_type(const X<T>& x, char (*)[std::is_base_of<T, X<T>>::value] = 0)
{
    std::cout << "Base: " << typeid(T).name() << "\n";
    print_type<T>(x);
}

template <typename T>
void print_type(const T&) {}

This might work for you (if I understood the question correctly). I got it working with gcc, but think it should work even in VS2010.

void printTypeComponents(const Blank&)
{
  std::cout << "composed of Blank\n";
}

template <typename T>
void printTypeComponents(const A<T>&)
{
  std::cout << "composed of A\n";
  printTypeComponents(T());
}

template <typename T>
void printTypeComponents(const B<T>&)
{
  std::cout << "composed of B\n";
  printTypeComponents(T());
}

template <typename T>
void printTypeComponents(const C<T>&)
{
  std::cout << "composed of C\n";
  printTypeComponents(T());
}

The advantage is that you do not need any typedef s inside the classes. If you want, you can put the logic inside printTypeComponentsImpl (or something like that) and have printTypeComponents delegate to that function.

You can avoid creating the temporaries, but since you cannot partially specialize functions, you'll have to move everything inside a struct and use that. If you want, I can put code example here.

edit: You could actually automate it a little bit with typeid(x).name() , provided you can extract the name of class template from it (named getTemplateName here).

template <template <typename> class T, typename U>
void printTypeComponents(const T<U>&)
{
  std::cout
    << "composed of "
    << getTemplateName(typeid(T<DummyClass>).name())
    << '\n';
  printTypeComponents(U());
}

For those interested, here 's gcc specific example.

Here is a template unraveller that uses variadic typenames. You can probably make it work in VS2010 with the usual macro tricks (eg like in the pretty-printer .)

template <typename T> class A : public T {};
template <typename T> class B : public T {};
template <typename T> class C : public T {};

struct NullType {};


#include <tuple>
#include <iostream>

template <typename ...Args> struct Concat;

template <typename T, typename ...Args>
struct Concat<T, std::tuple<Args...>>
{
  typedef std::tuple<T, Args...> type;
};

template <typename> struct Unravel;

template <typename T, template <typename> class X>
struct Unravel<X<T>>
{
  typedef typename Concat<X<T>, typename Unravel<T>::type>::type type;
};

template <template <typename> class X>
struct Unravel<X<NullType>>
{
  typedef std::tuple<X<NullType>> type;
};

template <typename T> struct printArgs;

template <typename T, typename ...Args>
struct printArgs<std::tuple<T, Args...>>
{
  static void print() { std::cout << "Have type." << std::endl; printArgs<std::tuple<Args...>>::print(); }
};

template <typename T>
struct printArgs<std::tuple<T>>
{
  static void print() { std::cout << "Have type." << std::endl; }
};

int main()
{
  typedef A<B<C<NullType>>> CType;
  printArgs<Unravel<CType>::type>::print();
}

It won't print anything exciting, so at the moment you just get one line per inheritance, but if you partially-specialize printArgs you can print specific information for your types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM