Использование SFINAE для определения POD-типа типа в C ++

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

Это предварительное использование SFINAE для создания эквивалента для класса шаблона is_pod, который существует в TR1 (в VS2005 еще нет TR1). Его член value должен иметь значение 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 имеют значение true.


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


person Fabio Ceconello    schedule 10.02.2009    source источник


Ответы (3)


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

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

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

Наверное, поэтому в документации Boost есть:

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

person jpalecek    schedule 11.02.2009

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

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

person MSN    schedule 11.02.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 за вас - если вы не пытаетесь реализовать свою собственную библиотеку или по какой-либо причине.

person Dean Michael    schedule 10.02.2009
comment
Я попытался использовать другой тип, а не пустую структуру, которую вы предложили, с помощью char *, но безрезультатно. Я просто попытался использовать ваш пример, но он дает тот же результат (верно как для POD, так и для не-POD). - person Fabio Ceconello; 11.02.2009
comment
Что касается enable_if, я рассматривал аналогичный подход, но это заставило бы меня вручную выбрать типы, которые являются / не являются POD, и я бы предпочел возложить эту нагрузку на компилятор. - person Fabio Ceconello; 11.02.2009
comment
Я также знаю, что у Boost есть шаблон, похожий на is_pod (на самом деле, большая часть TR1 была вдохновлена ​​Boost, и, вероятно, это еще один пример), но я бы предпочел не добавлять зависимость к функции, которая в будущем должна быть частью в любом случае стандарт. - person Fabio Ceconello; 11.02.2009