2009-02-10 5 views
4

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

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


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

ответ

4

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

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

  • массивов недействительные, ссылки, функция или недействительных размера
  • элемента типа, который не является типом
  • указателей на ссылки, ссылки на ссылки, ссылки на аннулированию
  • указателя на член типа неклассовой
  • недействительных конверсий значения параметров шаблона
  • типов функций с аргументами типа недействительного
  • Const/volati Функция ле типа

Это, вероятно, почему в Boost, документации, есть:

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

1

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

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 е, чтобы сделать ваш SFINAE для вас - если вы не пытаетесь реализовать свою собственную библиотеку или по какой-то причине.

+0

Я попытался использовать другой тип, а не пустую структуру, которую вы предложили, char *, безрезультатно. Я просто попытался использовать ваш пример, но он дает тот же результат (истинный как для POD, так и для не-POD). –

+0

О enable_if, я рассматривал аналогичный подход, но это заставило бы меня вручную выбрать типы, которые являются/не являются POD, и мое предпочтение было бы дать это бремя для компилятора. –

+0

Я также знаю, что Boost имеет шаблон аналогично is_pod (на самом деле, большая часть TR1 была вдохновлена ​​Boost и, вероятно, это еще один пример), но я бы предпочел не добавлять зависимость от функции, которая в будущем должна быть частью стандарта в любом случае. –

2

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

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

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