Как узнать, является ли аргумент, который передается функции, классом, объединением или перечислением в c ++? - PullRequest
3 голосов
/ 16 января 2011

Я хочу определить оператор << для всех перечислений, чтобы подсчитать значение и вывести его как это перечисление: </p>

код:

enum AnyEnum{A,B,C};
AnyEnum enm = A;
cout << enm <<endl;

вывод:

This is an enum which has a value equal to 0

Я знаю способ сделать это с помощью библиотеки Boost, используя is_enum struct.Но я не понимаю, как это работает.Поэтому, в общем, меня интересует, как определить, является ли проверяемый тип класса, типа объединения или перечисления (во время компиляции).

Ответы [ 4 ]

5 голосов
/ 16 января 2011

При определении типов классов вы можете использовать тот факт, что указатели на элементы существуют

template<typename A, typename B>
struct issame { };

template<typename A>
struct issame<A, A> { typedef void type; };

template<typename> struct tovoid { typedef void type; };

template<typename T, typename = void>
struct isclass { static bool const value = false; };

template<typename C>
struct isclass<C, typename tovoid<int C::*>::type> {
  static bool const value = true;
};

Вы не можете обнаружить разницу между объединенным и не объединенным классом. По крайней мере, я не знаю как, и повышение не знает также.

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

template<typename E, typename = void> 
struct isenum { 
  struct No { char x; };
  struct Yes { No n1; No n2; };

  struct nullsink {};
  static No checkI(nullsink*); // accept null pointer constants
  static Yes checkI(...);

  static Yes checkE(int);
  static No checkE(...);

  static bool const value = (sizeof(checkI(E())) == sizeof(Yes)) && 
                            (sizeof(checkE(E())) == sizeof(Yes));
};

// class
template<typename E>
struct isenum<E, typename tovoid<int E::*>::type> {
  static bool const value = false;
};

// reference
template<typename R>
struct isenum<R&, void> {
  static bool const value = false;
};

// function (FuntionType() will error out).
template<typename F>
struct isenum<F, typename issame<void(F), void(F*)>::type> {
  static bool const value = false;
};

// array (ArrayType() will error out)
template<typename E>
struct isenum<E[], void> {
  static bool const value = false;
};
template<typename E, int N>
struct isenum<E[N], void> {
  static bool const value = false;
};

Быстрый и грязный тест (работает на GCC / Clang / Comeau):

enum A { };
struct B { };
typedef int &C;
typedef void D();
typedef int E;
typedef long F;
typedef int const G;
typedef int H[1];

template<typename T, bool E>
struct confirm { typedef char x[(T::value == E) ? 1 : -1]; };

int main() {
  confirm< isenum<A>, true >();
  confirm< isenum<B>, false >();
  confirm< isenum<C>, false >();
  confirm< isenum<D>, false >();
  confirm< isenum<E>, false >();
  confirm< isenum<F>, false >();
  confirm< isenum<G>, false >();
  confirm< isenum<H>, false >();
}
2 голосов
/ 16 января 2011

Меня интересует, как определить, является ли проверяемый тип класса, типа объединения или перечисления (во время компиляции).

boost :: type_traits

Даже C ++ TR1 имеет заголовок <type_traits> для поддержки этой функции. В C ++ 0x все будет намного лучше.

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

template<typename T>struct Check_If_T_Is_Class_Type
{
    template<typename C> static char func (char C::*p);
    template<typename C> static long func (...);
    enum{val = CHECKER(func,Check_If_T_Is_Class_Type)};
};

МАКРО CHECKER - это

#define CHECKER(func_name,class_name) \
sizeof(class_name<T>::template func_name<T>(0)) == 1

Чтобы понять, как работают type_traits, вам необходимо иметь базовые знания о шаблонах, включая метапрограммирование шаблонов и SFINAE.

0 голосов
/ 16 января 2011

Обычно это делается с помощью хуков компилятора. Компилятор имеет специальные функции, которые «заполняют» шаблон соответствующим значением (по крайней мере, в C ++ 0x, где type_traits был стандартизован) Например, черта is_pod использует хук компилятора __is_pod в VC 10 для получения соответствующей информации.

0 голосов
/ 16 января 2011

невозможно узнать тип переменной во время компиляции.

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