Без поддержки C ++ 11 (decltype
) это может работать:
SSCCE
#include <iostream>
using namespace std;
struct A { void foo(void); };
struct Aa: public A { };
struct B { };
struct retA { int foo(void); };
struct argA { void foo(double); };
struct constA { void foo(void) const; };
struct varA { int foo; };
template<typename T>
struct FooFinder {
typedef char true_type[1];
typedef char false_type[2];
template<int>
struct TypeSink;
template<class U>
static true_type &match(U);
template<class U>
static true_type &test(TypeSink<sizeof( matchType<void (U::*)(void)>( &U::foo ) )> *);
template<class U>
static false_type &test(...);
enum { value = (sizeof(test<T>(0, 0)) == sizeof(true_type)) };
};
int main() {
cout << FooFinder<A>::value << endl;
cout << FooFinder<Aa>::value << endl;
cout << FooFinder<B>::value << endl;
cout << FooFinder<retA>::value << endl;
cout << FooFinder<argA>::value << endl;
cout << FooFinder<constA>::value << endl;
cout << FooFinder<varA>::value << endl;
}
Как это, надеюсь, работает
A
, Aa
и B
- это рассматриваемые предложения, Aa
- это особое, которое наследует искомого члена.
В FooFinder
true_type
и false_type
являются заменами для соответствующих классов C ++ 11. Также для понимания шаблонного метапрограммирования они раскрывают саму основу SFINAE-sizeof-трюка.
TypeSink
- это структура шаблона, которая позже используется для погружения интегрального результата оператора sizeof
в создание экземпляра шаблона для формирования типа.
Функция match
- это еще один вид шаблона SFINAE, который не имеет общего аналога. Следовательно, он может быть создан только в том случае, если тип его аргумента соответствует типу, для которого он был специализирован.
Обе функции test
вместе с объявлением enum, наконец, образуют центральный шаблон SFINAE. Существует универсальный, использующий многоточие, которое возвращает false_type
, и аналог с более конкретными аргументами, чтобы иметь приоритет.
Чтобы иметь возможность создавать экземпляр функции test
с аргументом шаблона T
, необходимо создать экземпляр функции match
, так как ее тип возврата требуется для создания экземпляра аргумента TypeSink
. Предостережение заключается в том, что &U::foo
, будучи заключенным в аргумент функции, является , а не , на который ссылаются из специализации аргумента шаблона, поэтому поиск унаследованного члена все еще происходит.