std :: enable_if, специализация шаблона и наследование - PullRequest
3 голосов
/ 21 марта 2012

Я хотел бы спросить вас о некоторых советах по поводу этого кода. Это работает, но я думаю, что это может быть написано более элегантным способом. Это кусок кода на C ++ 11, так что имейте это в виду при компиляции;)!

#include <iostream>
#include <type_traits>
#include <typeinfo>

using namespace std;

class A {};
class B: public A {};

class C {};
class D: public C {};

class E: public A, public C {};

template<class T, typename = void>
class Example;

template<class T>
class Example<T, typename enable_if<is_base_of<A, T>::value and not is_base_of<C, T>::value>::type>
{
  public:
    string a() const
    {
      return string(typeid(T).name()) + " have A as base class";
    }
};

template<class T>
class Example<T, typename enable_if<not is_base_of<A, T>::value and is_base_of<C, T>::value>::type>
{
  public:
    string b() const
    {
      return string(typeid(T).name()) + " have C as base class";
    }
};

template<class T>
class Example<T, typename enable_if<is_base_of<A, T>::value and is_base_of<C, T>::value>::type> :
    public Example<A>,
    public Example<C>
{
};

int
main()
{
  Example<B> example1;
  Example<D> example2;
  Example<E> example3;

  cout << example1.a() << endl;
  //cout << example1.b() << endl;   It must raise a compile error
  //cout << example2.a() << endl;   It must raise a compile error
  cout << example2.b() << endl;
  cout << example3.a() << endl;
  cout << example3.b() << endl;
}

Как видите, я пытаюсь написать шаблон класса, который может обрабатывать классы, полученные из A и C . Проблема в том, что A и C наследуются как для класса E . На самом деле мы могли бы иметь что-то вроде этого ...

template<class T>
class Example<T, typename enable_if<is_base_of<A, T>::value> { /* ... */ };

template<class T>
class Example<T, typename enable_if<is_base_of<C, T>::value> { /* ... */ };

... но произойдет сбой, когда класс (например, E ) унаследует либо A и C .

Есть идеи по улучшению кода? Спасибо

1 Ответ

4 голосов
/ 21 марта 2012

Более простой способ - использовать static_assert.

template <typename T>
class Example
{
public:
    std::string a() const
    {
        static_assert(std::is_base_of<A, T>::value, "T must derive from A to use a()");
        return std::string(typeid(T).name()) + " have A as base class";
    }

    std::string b() const
    {
        static_assert(std::is_base_of<C, T>::value, "T must derive from C to use b()");
        return std::string(typeid(T).name()) + " have C as base class";
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...