Использование SFINAE для определения модуля типа в C ++
-
22-08-2019 - |
Вопрос
Оригинальное название здесь было Обходной путь для ошибки SFINAE в VS2005 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), поэтому оба a и b оцениваются как true .
Спасибо за ответы, опубликованные ниже.Внимательно прочитав их (и код) Я понял, что то, что я пытался сделать, на самом деле было неправильным подходом.Идея состояла в том, чтобы объединить поведение SFINAE с адаптацией к шаблону must_be_pod должен быть (который я нашел в книге Несовершенный C++, но его можно найти и в других местах).На самом деле, для этого потребовался бы довольно специфический набор правил для SFINAE, которые, очевидно, не соответствуют определению стандарта.В конце концов, на самом деле это не ошибка в VS.
Решение
Самая большая проблема с вашим подходом заключается в том, что вы не используете SFINAE здесь - SFINAE применяется только к типам параметров и возвращаемому типу здесь.
Однако из всех ситуаций SFINAE в стандарте ни одна не применима к вашей ситуации.Они такие
- массивы с нулевыми значениями, ссылками, функциями или недопустимого размера
- элемент типа, который не является типом
- указатели на ссылки, ссылки на ссылки, ссылки на недействительные
- указатель на элемент неклассового типа
- недопустимые преобразования параметров значения шаблона
- типы функций с аргументами типа void
- тип функции const/volatile
Вероятно, именно поэтому в документации Boost есть:
Без некоторой (пока неуказанной) помощи от компилятора ispod никогда не будет сообщать, что класс или структура является POD;это всегда безопасно, если возможно неоптимально.В настоящее время (май 2005) только MWCW 9 и Visual C ++ 8 имеют необходимый компилятор-_intrinsics.
Другие советы
Это также не работает с VS2008, но я подозреваю, что вы это тоже знали.SFINAE предназначен для вывода аргументов шаблона для параметров шаблона;на самом деле вы не можете определить тип чего-либо, что раскрывает конструкторскую принадлежность типа, даже если вы можете создать тип, несовместимый с другим типом (т. Е. объединения не могут использовать non-POD).
Фактически, VS 2008 использует поддержку компилятором признаков для реализации std::tr1::type_traits
.
Я не уверен в том, как вы пытаетесь сделать 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))};
};
Возможно, вы также захотите взглянуть на Повышение.Enable_i Включитьf, чтобы сделать ваш SFINAE за вас - если только вы не пытаетесь реализовать свою собственную библиотеку или по какой-либо причине.