Я новичок в написании кода метапрограммирования шаблона (а не просто в его чтении). Так что я столкнулся с некоторыми проблемами нубов. Один из них довольно хорошо резюмирован в сообщении, не относящемся к SO, под названием " Что случилось с моим SFINAE? ", который я буду преобразовывать в C ++ 11 следующим образом:
(Примечание: в этом примере «мысленного эксперимента» я дал методам разные имена только для помощи в диагностике ошибок. См. @R .MartinhoЗаметки Фернандеса о том, почему вы на самом деле не выбрали бы этот подход на практике при отсутствии перегрузок.)
#include <type_traits>
using namespace std;
template <typename T>
struct Foo {
typename enable_if<is_pointer<T>::value, void>::type
valid_if_pointer(T) const { }
typename disable_if<is_pointer<T>::value, void>::type
valid_if_not_pointer(T) const { }
};
int main(int argc, char * argv[])
{
int someInt = 1020;
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
return 0;
}
@Alf говорит, что с SFINAE произошло следующее: «Этого там не было вообще», и предлагает компилировать, но шаблонизирует функции вместо класса. Это может быть правильным для некоторых ситуаций, но не для всех. (Например: я специально пытаюсь написать контейнер, который может содержать типы, которые могут или не могут быть копируемыми, и мне нужно включать и выключать методы в зависимости от этого.)
В качестве обходного пути я попробовал это ... и, похоже, он работает правильно.
#include <type_traits>
using namespace std;
template <typename T>
struct FooPointerBase {
void valid_if_pointer(T) const { }
};
template <typename T>
struct FooNonPointerBase {
void valid_if_not_pointer(T) const { }
};
template <typename T>
struct Foo : public conditional<
is_pointer<T>::value,
FooPointerBase<T>,
FooNonPointerBase<T> >::type {
};
int main(int argc, char * argv[])
{
int someInt = 1020;
#if DEMONSTRATE_ERROR_CASES
Foo<int*>().valid_if_not_pointer(&someInt);
Foo<int>().valid_if_pointer(304);
#else
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
#endif
return 0;
}
Но если это не нарушено (не так ли?), это определенно не соответствует хорошей общей методологии включения и выключения методов в шаблонном классе на основе анализа типа на наличие признаков. Есть ли лучшее решение?