Я столкнулся с idiom Member Detector в C++, что является признаком типа, чтобы узнать, содержит ли класс член определенного имени. Но связанный пример не работает, как я ожидал, если тип не является классом: мне нужен результат false
для любого типа, отличного от класса. Возможное решение, конечно, что-то вроде этого, используя boost::is_class<T>
:SFINAE для создания экземпляра типа
template<typename T>
struct general_DetectX : boost::mpl::and_<
boost::is_class<T>,
DetectX<T> >::type
{ };
bool hasX = general_DetectX<int>::value; // hasX = false
Но этот вопрос о том, почему оригинал DetectX<T>
выдает ошибки, вместо того, чтобы делать SFINAE вещь. Вот выдержка из соответствующих частей связанного кода (местные Структуры Fallback
и Check<U,U>
и определение типов ArrayOfOne
, ArrayOfTwo
и type
удалены для краткости):
template<typename T>
class DetectX
{
struct Derived : T, Fallback { };
template<typename U>
static ArrayOfOne & func(Check<int Fallback::*, &U::X> *);
template<typename U>
static ArrayOfTwo & func(...);
public:
enum { value = sizeof(func<Derived>(0)) == 2 };
};
Можно видеть, что DetectX::Derived
используется вне любого разрешения перегрузки , поэтому правило SFINAE для обработки ошибок никогда не вызывается. Но это может быть изменено, где использование Derived
делает случаться как часть разрешения перегрузки:
template<typename T>
class DetectX
{
template<typename U>
struct Derived : U, Fallback { };
template<typename U>
static ArrayOfOne & func(Check<int Fallback::*, &Derived<U>::X> *);
template<typename U>
static ArrayOfTwo & func(...);
public:
enum { value = sizeof(func<T>(0)) == 2 };
};
Derived<T>
шаблон только инстанцирован при попытке создать экземпляр первого func()
перегрузки, так почему же я до сих пор получаю ошибки даже для модифицированной версии? Вот пример:
$ g++ --version | head -n1
g++ (GCC) 4.8.2
$ g++ -c demo.cxx
demo.cxx: In instantiation of 'struct DetectX<int>::Derived<int>':
demo.cxx:16:53: required by substitution of 'template<class U> static char (& DetectX<T>::func(DetectX<T>::Check<int DetectX<T>::Fallback::*, (& DetectX<T>::Derived<U>::X)>*))[1] [with U = U; T = int] [with U = int]'
demo.cxx:24:31: required from 'class DetectX<int>'
demo.cxx:27:25: required from here
demo.cxx:7:12: error: base type 'int' fails to be a struct or class type
struct Derived : U, Fallback { };
^
Это не удается, потому что замена происходит в списке базовых классов *, где * любая ошибка приводит к жесткой ошибке, а не к мягкой ошибке (SFINAE). Другими словами, SFINAE не встречается в базовых классах. – Nawaz
@Nawaz Спасибо за комментарий, представляющий меня жесткие и мягкие ошибки. Но мне нужна ссылка на http://stackoverflow.com/questions/15260685, предоставленную Jarod42 в его ответе, чтобы получить контекст. –