2013-03-21 2 views
1

Я хотел бы создать шаблон, который проверяет, является ли тип класса примитивным или нет (int, char, float, float ***, ect ...). Причина этого заключается в том, чтобы предотвратить попытку другого шаблона расширить примитивы и вызвать ошибку времени компиляции. До сих пор у меня есть что-то вроде:Создать шаблон is_primitive или is_inheritable

#include <typeinfo> 
template<typename T> 
struct is_primitive{ 
    const static bool value=std::is_fundamental<T>::value; 
}; 

Очевидно, что это просто форматирует результат is_fundamental прямо сейчас. Я хотел бы добавить remove_pointer, remove_reference, ect ..., чтобы удалить все эти дополнительные модификаторы входного класса. Что нужно сделать, чтобы сделать T максимально открытым?

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

template<typename T> 
struct is_inheritable{ 
    const static bool value=???; 
}; 

Но я уверен, что множество uninheritable классов составляет множество примитивных классов.

+3

звучит, как вы хотите [ 'is_fundamental'] (http://en.cppreference.com/w/cpp/types/ is_fundamental). Обратите внимание, что (как написано в вашем вопросе) тип класса никогда не является примитивным (фундаментальным), поскольку тип класса всегда вводится через 'class' или' struct'. – GManNickG

+0

Ничего себе я не знаю, почему я это пропустил, но я не думаю, что он ловит все ссылки, части указателя и другие вещи, о которых я мог бы не знать (все еще довольно новый для реального мира C++). Я обновляю свой вопрос с помощью is_fundamental. – Suedocode

+0

«baring» of 'T' обычно называется« Unqualified », и этого достаточно, чтобы связать' RemoveCv > '- ссылки не могут быть cv-квалификацией, поэтому они должны быть на верхнем уровне. У вас не может быть ссылок на ссылки или указатели на ссылки, поэтому опять же они должны быть на высшем уровне. После этого просто разделите cv-qualificaiton. (Cv-qual означает const и/или volatile-qualified.) – Xeo

ответ

5

Мне кажется, что вы хотите std::is_class<T>. Можно наследовать только типы классов. Это схема, которая изображает C++ 11 типа классификационных признаков: Here http://howardhinnant.github.io/TypeHiearchy.pdf

http://howardhinnant.github.io/TypeHiearchy.pdf

+0

Это замечательно. С 2007 года что-то изменилось, что может привести к устареванию? (EDIT: Например, отсутствует разделитель 'is_signed', целеустремленный, недосмотр или устаревший?) – GManNickG

+0

@GManNickG: Я не проверял дважды, но я думаю, что нет. Обратите внимание, что на этой диаграмме представлены только модели 20.9.4.1. Категории первичного типа и 20.9.4.2. Характеристики композитного типа. Первый описывает все «листовые» типы в типах 3.9, а последний описывает типы нелистов в этом дереве. 'is_signed', а также многие другие черты входят в 20.9.4.3. Свойства типа, ни одна из которых не представлена ​​на этой диаграмме. Предполагаемый инвариант состоит в том, что каждый тип в C++ вписывается в один из категорий первичного типа (листы на приведенной выше диаграмме). –

+0

Делает смысл, спасибо! – GManNickG

0
template <typename T> 
struct remove_all { typedef typename std::remove_cv<T>::type type; }; 
template <typename T> 
struct remove_all<T*> { typedef typename remove_all<T>::type type; }; 
template <typename T> 
struct remove_all<T&> { typedef typename remove_all<T>::type type; }; 
template <typename T> 
struct remove_all<T&&> { typedef typename remove_all<T>::type type; }; 

template<typename T> 
struct is_primitive{ 
    typedef typename remove_all<T>::type TF; 
    const static bool value=std::is_fundamental<TF>::value; 
}; 

remove_all struct discussion найдено here.

+1

'std :: cout << std :: is_same :: type, int *> :: value' - ваш' remove_all' вводит в заблуждение? – Yakk

+0

Предполагается удалить все указатели и ссылочные атрибуты, однако я был немного ленив с cvs like const. Поэтому он должен преобразовать int * const -> int, но я думаю, что постфикс-константа закручивает его вверх – Suedocode

1

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

Попробуйте использовать is_constructible или какой-либо связанный тип признака:

// check that T::T(std::string,int); exists: 
std::is_constructible< T, std::string, int >::value 

// or these direct traits for the usual suspects... 
std::is_default_constructible<T>::value 
std::is_copy_constructible<T>::value 
std::is_move_constructible<T>::value 

Для другого вопроса, если он актуален после того, как выше, проверить std::decay и объединить его с другими признаками раздеться типа по мере необходимости:

template< typename T, typename = void > 
struct strip 
{ 
    typedef T type; 
}; 

template< typename T > 
struct strip< T, typename std::enable_if< 
    !std::is_same< typename std::decay<T>::type, T >::value 
>::type > 
    : strip< typename std::decay<T>::type > 
{ 
}; 

template< typename T > 
struct strip< T, typename std::enable_if< 
    std::rank<T>::value != 0 
>::type > 
    : strip< typename std::remove_all_extents<T>::type > 
{ 
}; 

template< typename T > 
struct strip< T, typename std::enable_if< std::is_pointer<T>::value >::type > 
    : strip< typename std::remove_pointer<T>::type > 
{ 
}; 

typedef const int*(&Test)[42]; 
static_assert(std::is_same< typename strip<Test>::type, int >::value, ""); 

но couse вам нужно выяснить, что именно подходит в вашем случае.

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