Использование SFINAE для обнаружения POD-ности типа в C ++ - PullRequest
4 голосов
/ 11 февраля 2009

Оригинальное название здесь было Обходной путь для ошибки SFINAE в VS2005 C ++

Это предварительное использование SFINAE для создания эквивалента для класса шаблона is_pod, существующего в TR1 (в VS2005 еще нет TR1). Он должен иметь value member true, если параметр шаблона имеет тип POD (включая примитивные типы и составленные из них структуры), и false, если это не так (как с нетривиальными конструкторами).

template <typename T> class is_pod
{
  public:

    typedef char Yes;
    typedef struct {char a[2];} No;

    template <typename C> static Yes test(int)
    {
      union {T validPodType;} u;
    }
    template <typename C> static No test(...)
    {
    }
    enum {value = (sizeof(test<T>(0)) == sizeof(Yes))};
};

class NonPOD
{
  public:
    NonPod(const NonPod &);
    virtual ~NonPOD();
};

int main()
{
  bool a = is_pod<char>::value;
  bool b = is_pod<NonPOD>::value;
  if (a) 
    printf("char is POD\n");
  if (b)
    printf("NonPOD is POD ?!?!?\n");
  return 0;
}

Проблема в том, что не только VS 2005 не имеет TR1, он не будет заботиться о объединении выше (которое не должно быть допустимым, если параметр шаблона не является POD), поэтому и a, и b оценивают как правда.


Спасибо за ответы, размещенные ниже. Внимательно прочитав их (и код), я понял, что то, что я пытался сделать, было действительно неправильным подходом. Идея заключалась в том, чтобы объединить поведение SFINAE с адаптацией к шаблону must_be_pod (который я нашел в книге Несовершенный C ++ , но его можно найти и в других местах). На самом деле, это потребует совершенно определенного набора правил для SFINAE, который, очевидно, не соответствует стандарту. В конце концов, это не совсем ошибка в VS.

Ответы [ 3 ]

4 голосов
/ 11 февраля 2009

Самая большая проблема с вашим подходом в том, что вы здесь не выполняете SFINAE - здесь SFINAE применяется только к типам параметров и типам возвращаемых данных.

Однако из всех ситуаций SFINAE в стандарте ни одна не применима к вашей ситуации. Они

  • массивы void, ссылок, функций или недопустимого размера
  • член типа, который не является типом
  • указатели на ссылки, ссылки на ссылки, ссылки на void
  • указатель на член неклассного типа
  • недопустимые преобразования параметров значения шаблона
  • типы функций с аргументами типа void
  • Тип постоянной / летучей функции

Возможно, поэтому в документации Boost есть:

Без некоторой (пока не уточненной) помощи от компилятора, ispod никогда не будет сообщить, что класс или структура является POD; это всегда безопасно, если возможно неоптимальный. В настоящее время (май 2005 г.) только MWCW 9 и Visual C ++ 8 имеют необходимый компилятор-_intrinsics.

2 голосов
/ 11 февраля 2009

Это не работает и с VS2008, но я подозреваю, что вы тоже это знали. SFINAE для вывода аргументов шаблона для параметров шаблона; вы не можете на самом деле определить тип чего-то, что показывает конструкторский тип, даже если вы можете создать тип, который несовместим с другим типом (т. е. объединения не могут использовать не POD).

Фактически, VS 2008 использует поддержку компилятора для признаков для реализации std::tr1::type_traits.

1 голос
/ 11 февраля 2009

Я не уверен, как вы пытаетесь сделать SFINAE здесь, так как is_pod<T>::test(...) будет соответствовать is_pod<T>::test(0). Возможно, если вы используете другой тип вместо int, вы получите лучшее соответствие:

template <typename T> class is_pod
{
  struct my_special_type { };
  public:
    typedef char Yes;
    typedef struct {char a[2];} No;

    template <typename C> static Yes test(my_special_type)
    {
      union {T validPodType;} u;
    }

    template <typename C> static No test(...)
    {
    }
    enum {value = (sizeof(test<T>(my_special_type())) == sizeof(Yes))};
};

Возможно, вы захотите взглянуть на Boost.Enable_i f, чтобы выполнить свой SFINAE за вас - если только вы не пытаетесь реализовать свою собственную библиотеку или по какой-либо причине.

...