【问题标题】:How to find, from which template-layers is object composed of?如何找到对象由哪些模板层组成?
【发布时间】:2011-08-09 18:19:42
【问题描述】:

如何使用模板,在使用模板层时,如何找出类型是由哪些类型组成的?

让我们来

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);
}

我附上了我的尝试,当然是错的(仅当对象由所有测试类型组成时才有效,因为测试类型确实存在),但您可以从中轻松看出我的目标是什么

#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);
}

我正在使用 MSVC2010

谢谢!

编辑: 我实际上对类型的名称并不感兴趣......我想像这样使用它:

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

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

【问题讨论】:

  • @relax - 或虚函数...

标签: c++ templates c++11 metaprogramming typetraits


【解决方案1】:

我的尝试(没有使用 C++0x 特性)

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

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;
}

测试代码:

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

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

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

输出:

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

在线演示:http://ideone.com/T5nD4

【讨论】:

  • 谢谢,但是当尝试在 VS2010 中编译它时,我收到了error C2872: is_same : ambiguous symbol。由于我对这种编程不是很熟悉,所以我无法自己修复它。你能帮帮我吗?
  • @relaxxx:删除using namespace std,或删除自定义is_same 并使用&lt;type_traits&gt; 中的std::is_same(您也可以在原始帖子中使用std::is_base_of)。这就是为什么一个人永远不要顺便写using namespace std
  • @Alexandre 谢谢你,它的工作原理......现在我需要一些重要的时刻来理解,分裂发生了什么(以及如何)......然后我会看看你和其他答案跨度>
  • 小伙伴们可以看看stackoverflow.com/questions/7013286/…
【解决方案2】:

利用你的结构,怎么样:

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&) {}

【讨论】:

  • 那个编辑更好,但你只得到第一垒。 print_type 应该是递归的。
  • @Mooing:授予。获取类型列表并不容易,因为 VS2010 没有可变参数模板。并且键入模板不是您可以做的事情。
  • @Mooing:不完全是。您必须使用 SFINAE 将模板参数与作为基类的模板参数区分开来。我更新了代码。
【解决方案3】:

这是一个使用可变类型名称的模板分解器。您可以使用通常的宏技巧(例如like in the pretty-printer)使其在 VS2010 中工作。

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();
}

它不会打印任何令人兴奋的东西,所以目前您每个继承只得到一行,但如果您部分专门化 printArgs,您可以打印您的类型的特定信息。

【讨论】:

    【解决方案4】:

    这可能对您有用(如果我正确理解了这个问题)。我让它与 gcc 一起工作,但认为它甚至在 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());
    }
    

    优点是类中不需要任何typedefs。如果需要,您可以将逻辑放入 printTypeComponentsImpl(或类似的东西)中,并让 printTypeComponents 委托给该函数。

    您可以避免创建临时对象,但由于您不能部分专门化函数,因此您必须将所有内容移动到结构中并使用它。如果你愿意,我可以在这里放代码示例。

    编辑:您实际上可以使用 typeid(x).name() 将其自动化一点,前提是您可以从中提取类模板的名称(此处命名为 getTemplateName)。

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

    对于那些感兴趣的人,here 的 gcc 特定示例。

    【讨论】:

      猜你喜欢
      • 2015-01-29
      • 1970-01-01
      • 2015-11-04
      • 2017-06-21
      • 2010-12-10
      • 2018-03-21
      • 2010-12-26
      • 2019-12-27
      • 1970-01-01
      相关资源
      最近更新 更多