使用模板化基础编译时间类选择器

时间:2012-11-05 13:46:36

标签: c++ templates

给出以下代码序列:

#include <iostream>

using namespace std;

template <typename T>
class Base
{
    public:
        T* t;
        void b() {}
};

class D1:
        public Base<D1>
{
    public:
        int d1;
};

class D2:
        public D1
{
    public:
        int d2;
};

template <typename T>
class Selector
{
    public:

        template <typename U>
        void a(Base<U>& base)
        {
            cout << __LINE__ << endl;
            base.b();
        }

        template <typename U>
        void a(U& u)
        {
            cout << __LINE__ << endl;
        }
};


int main()
{
    D2 derivated;
    Selector<D2> s;
    s.a(derivated);
    return 0;
}

我想检查一些类(D2)是否有基类(Base),是否继承了任何D2父类。 我无法让Selector找到最专业的成员函数。

2 个答案:

答案 0 :(得分:3)

您可以装配自己的特征来检查某个类型是否具有任何 Base<T>作为祖先。以下适用于我:

template <typename T> struct Foo { };

struct Bar : Foo<Bar> { };

struct Zip : Bar { };

#include <type_traits>

template <typename T>
class derives_from_any_foo
{
    typedef char yes;
    typedef char no[2];

    template <typename U>
    static yes & test(Foo<U> const &);

    static no & test(...);

public:
    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes);
};

#include <iostream>

int main()
{
    std::cout << "int: " <<  derives_from_any_foo<int>::value << "\n"
              << "Bar: " <<  derives_from_any_foo<Bar>::value << "\n"
              << "Zip: " <<  derives_from_any_foo<Zip>::value << "\n";
}

通常不需要为这种类型的检查要求任何对象实例;一切都只是静态的。如果您有一个对象,请使用decltype来获取其类型,或者添加一个类型推导辅助函数。

答案 1 :(得分:1)

这种情况正在发生,因为与U = D2相比U = D1是更好的候选者(即Base<D1>)。你将无法使用相同的函数定义来实现这一点,因为第一个替代方案总是超过第二个。

更新:如果您允许更改class Selector,请按以下SFINAE方式进行调整以使其正确:

template<bool> struct Bool;
template <typename T, typename = Bool<true> >
class Selector // <---- For general cases
{
public:
   template <typename U>
   void a(U& u)  // <---- choose normal funciton
   {   
     cout << __LINE__ << endl;
   }   
};
template <typename T>
class Selector<T,Bool<IsAnyPublicBaseof<T,Base>::value> >
{ // <---- For the cases like `class D2`
public:
  template <typename U>
  void a(Base<U>& base)  // <--- choose special function
  {   
    cout << __LINE__ << endl;
    base.b();
  }   
};

内部SFINAE是,

template<typename T, template<typename> class Base>
struct IsAnyPublicBaseOf
{
  typedef char (&yes)[2];

  template<typename X>
  static yes Check (Base<X>*);
  static char Check (...);

  static const bool value = (sizeof(Check((T*)0)) == sizeof(yes));
};

这是working demo完全您的代码。

另请注意,您无需确定Selector对象。只需将Selector::a()设为static方法,并使用法简单:

Selector<D2>::a(derivated);