2012-04-25 6 views
2

Я пытаюсь найти способ получить базовый класс параметра шаблона.Как получить T * от параметра шаблона T, T & или T *

Рассмотрим следующий класс:

template <class C> 
class Foo 
{ 
    public: 
     Foo(){}; 
     ~Foo(){}; 
     C* ptr; 
}; 

если C является ссылкой (например Test &), то PTR является тип C & *

Но мне нужно, чтобы получить указатель базовый класс, является ли C ссылкой, указателем или чем-то еще.

  • если C является Тест & затем PTR должны быть Test *,
  • если C является Test * затем PTR должен быть Test * ,
  • если C является Тест затем PTR должен быть Test * и т.д.

Есть в любом случае, чтобы получить «базовый» класс C, так что я могу создать указатель мне нужно?

+2

Что делать, если 'C' является' Test *** 'или' Test [1] [2] '? Или 'Test const *'? –

+0

У меня нет времени, чтобы написать полный ответ, но проверить специализацию частичного шаблона (например, Google) для ссылочных и указательных типов. – tmpearce

+0

Хорошие книги по этой теме: D. Vandevoorde, N.M. Josuttis «C++ templates. Полное руководство» и Alexandrescu «Современный дизайн C++: общие шаблоны программирования и дизайна».Эти книги содержат огромные примеры, подобные этому, и дают представление о методах метапрограммирования шаблонов, таких как черты и стратегии. – parallelgeek

ответ

2

Как насчет использования std::remove_reference?

#include <type_traits> 

template <class C> 
class Foo 
{ 
    public: 
     Foo(){}; 
     ~Foo(){}; 
     std::remove_reference<C>::type *ptr; 
}; 
3

ли это:

#include <type_traits> 

template <typename T> 
class Foo 
{ 
    typedef typename std::remove_pointer<typename std::decay<T>::type>::type C; 
    // ... 
}; 

decay удаляет ссылки и CV-квалификацию, и remove_pointer удаляет указатели.

8

Если вам действительно нужен базовый тип элемента, вы можете использовать рекурсивные приложения манипуляции черт типа удаления:

#include <type_traits> 

// precv = pointer, reference, extents, const, and volatile 
template <typename T> 
struct remove_precv 
{ 
    typedef typename std::remove_pointer< 
      typename std::remove_reference< 
      typename std::remove_all_extents< 
      typename std::remove_cv<T>::type>::type>::type>::type type; 
}; 

template <typename T, typename U> 
struct element_type_impl 
{ 
    typedef typename element_type_impl< 
      typename remove_precv<T>::type, T>::type type; 
}; 

template <typename T> 
struct element_type_impl<T, T> 
{ 
    typedef T type; 
}; 

template <typename T> 
struct element_type 
{ 
    struct null_type { }; 
    typedef typename element_type_impl<T, null_type>::type type; 
}; 

Например, element_type<int***[42]>::type является int.

+2

Вместо 'remove_precv', я думаю, что' std :: decay' тоже может работать здесь, как указано в ответе Kerrek SB. Я не был знаком с этой чертой манипуляции, и я не совсем уверен, каково ее поведение. –

+0

Распад также преобразует массивы и типы функций, которые могут быть нежелательными (конечно, в q мы имеем только классы). –

2

Вы можете сделать это с небольшим количеством шаблонов мета-программирования, например:

#include <cassert> 
#include <typeinfo> 

template <typename T> 
struct unpoint { 
    typedef T type; 
}; 

template <typename T> 
struct unpoint<T*> { 
    typedef typename unpoint<T>::type type; 
}; 

int main() { 
    int *a; 
    int **b; 
    int ***c; 
    int ****d; 

    const std::type_info& t1=typeid(unpoint<decltype(a)>::type); 
    const std::type_info& t2=typeid(unpoint<decltype(b)>::type); 
    const std::type_info& t3=typeid(unpoint<decltype(c)>::type); 
    const std::type_info& t4=typeid(unpoint<decltype(d)>::type); 
    assert(t1 == t2); 
    assert(t1 == t3); 
    assert(t1 == t4); 
} 

Где специализация unpoint удаляет указатель и рекурсивно вызывает себя до тех пор, пока не осталось в типе указателей.

Смежные вопросы