Можно ли выборочно определить тип в производном классе - PullRequest
2 голосов
/ 10 февраля 2011

У меня есть шаблон класса, который выглядит следующим образом:

template <Base>
struct foo : Base
{
  typedef int some_type;
};

, и у меня есть база, которая выглядит следующим образом:

struct some_base
{
  typedef float some_type;
};

Теперь foo<some_base>::some_type будет intпоскольку производное foo скроет Base::some_type.Что я хотел бы сделать, так это то, что если определено Base::some_type, используйте это еще, определите some_type локально в foo как 'int - поэтому вопрос в том, возможно ли это?

Я мог бы перевернуть отношения и избавить себя от головной боли, однако в реальном приложении это не очень логично ...

Ответы [ 3 ]

3 голосов
/ 10 февраля 2011

Все возможно с небольшим количеством метапрограммирования шаблона:)

Начните с написания метафункции, которая определяет, имеет ли тип вложенный тип с именем "some_type". Примерно так:

template <typename T>
struct has_some_type
{
    typedef char no;                    // type with sizeof == 1
    typedef struct { char x[2]; } yes;  // type with sizeof == 2

    template <typename X, typename Y = typename X::some_type>
    struct foo {};

    template <typename X>
    static yes test(foo<X>*);

    template <typename X>
    static no test(...);

    static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

Теперь вы можете сделать что-то подобное в производном классе:

template <typename T, bool has_some_type>
struct get_some_type;

template <typename T>
struct get_some_type<T, true>
{
    typedef typename T::some_type type;
};

template <typename T>
struct get_some_type<T, false>
{
    typedef int type;  // the default type
};

template <typename base>
class derived : base
{
    typedef typename get_some_type<base, has_some_type<base>::value>::type some_type;

    ...
};
2 голосов
/ 10 февраля 2011

Это должно работать:

struct sfinae_types
{
  struct yes { char x; };
  struct no  { char x[2]; };
};

template<class T>
class has_some_type : sfinae_types
{
  private:
    template<class U>
    static yes test(typename U::some_type *);
    template<class U>
    static no test(...);
  public:
    enum { value = (sizeof(yes) == sizeof(test<T>(0))) };
};

template<bool, class T, typename DT>
struct get_some_type
{
  typedef DT type;
};

template<class T, typename DT>
struct get_some_type<true, T, DT>
{
  typedef typename T::some_type type;
};

struct B1
{
};

struct B2
{
  typedef float some_type;
};

template<typename T>
struct D : T
{
  typedef typename get_some_type<has_some_type<T>::value, T, int>::type some_type;
};

#include<iostream>
#include<typeinfo>

int main()
{
  std::cout << has_some_type<B1>::value << std::endl;
  std::cout << typeid(D<B1>::some_type).name() << std::endl;
  std::cout << has_some_type<B2>::value << std::endl;
  std::cout << typeid(D<B2>::some_type).name() << std::endl;
  return(0);
}

И является небольшим изменением того, что HighCommander4 представил несколькими секундами выше ...

Я думаю, что boost :: mpl может пригодиться здесь и обеспечитьнекоторые полезные выражения TMP, которые я создал выше.

1 голос
/ 10 февраля 2011

Дайте struct foo дополнительный аргумент шаблона, по умолчанию int:

template <Base, Typedef = int>
struct foo : Base
{
  typedef Typedef some_type;
};

Тогда foo<some_base, some_base::some_type>::some_type равно some_base::some_type.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...